I am using Macports 1.7.1, and I don't want the latest port version, since it does not play nice with some other packages I want to build from source.
How can I force a particular version of a package installed from within macports "port" tool?
mac-osx
I am using Macports 1.7.1, and I don't want the latest port version, since it does not play nice with some other packages I want to build from source.
How can I force a particular version of a package installed from within macports "port" tool?
I apologise for directly answering everything, but I don't know any useful tutorials, FAQs, etc. Basically what follows is 8 years of making desktop apps (that I help distribute), frustration and googling:
1. How do I figure out what arguments to pass to ./configure?
Practice really. Autotools is easy enough as it is consistent. But there's plenty of stuff out there using cmake, or custom build scripts. Generally, you shouldn't have to pass anything to configure, it should figure out if your system can build foo-tool or not.
Configure and GNU tools all look in /, /usr and /usr/local for dependencies. If you install anything anywhere else (which makes things painful if the dependency was installed by MacPorts or Fink), you will have to pass a flag to configure or modify the shell's environment to help GNU tools find these dependencies.
2. How shared libraries work under OS X / Linux - where they live on the filesystem, how ./configure && make finds them, what actually happens when they are linked against
On Linux they need to be installed to a path that the dynamic linker can find, this is defined by the LD_LIBRARY_PATH
environment variable and the contents of /etc/ld.conf. On Mac it is the same for most open source software almost always (unless it is an Xcode Project). Except the env variable is DYLD_LIBRARY_PATH
instead.
There is a default path that the linker searches for libraries. It is /lib:/usr/lib:/usr/local/lib
You can supplement this by using the CPATH variable, or CFLAGS or any number of other environment variables really (conveniently complicated). I suggest CFLAGS like so:
export CFLAGS="$CFLAGS -L/new/path"
The -L parameter adds to the link path.
Modern stuff uses the pkg-config tool. Modern stuff you install also installs a .pc file that describes the library and where it is and how to link to it. This can make life easier. But it doesn't come with OS X 10.5 so you'll have to install that too. Also a lot of basic deps don't support it.
The act of linking is just "resolve this function at runtime", really it's a big string table.
3. What are the actual differences between a shared and a statically linked library? Why can't I just statically link everything (RAM and disk space are cheap these days) and hence avoid weird library version conflicts?
When you link to a static library file the code becomes part of your application. It would be like if there was one giant .c file for that library and you compiled it into your application.
Dynamic libraries have the same code, but when the app is run, the code is loaded into the app at runtime (simplified explanation).
You can statically link to everything, however, sadly hardly any build systems make this easy. You'd have to edit build system files manually (eg. Makefile.am, or CMakeLists.txt). However this is probably worth learning if you regularly install things that require different versions of libraries and you are finding installing dependencies in parallel difficult.
The trick is to change the link line from -lfoo to -l/path/to/static/foo.a
You can probably find and replace. Afterwards check the tool doesn't link to the .so or dylib using ldd foo or otool -L foo
Another problem is not all libraries compile to static libraries. Many do. But then MacPorts or Debian may have decided not to ship it.
4. How can I tell what libraries I have installed, and what versions?
If you have pkg-config files for those libraries it is easy:
pkg-config --list-all
Otherwise you often can't easily. The dylib may have a soname (ie. foo.0.1.dylib, the soname is 0.1) that is the same as the library's version. However this is not required. The soname is a binary computability feature, you have to bump the major part of the soname if you change the format of the functions in the library. So you can get eg. version 14.0.5 soname for a 2.0 library. Although this is not common.
I got frustrated with this sort of thing and have developed a solution for this on Mac, and I'm talking about it next.
5. How can I install more than one version of a library without breaking my normal system?
My solution to this is here: http://github.com/mxcl/homebrew/
I like installing from source, and wanted a tool that made it easy, but with some package management. So with Homebrew I build, eg. wget myself from source, but make sure to install to a special prefix:
/usr/local/Cellar/wget/1.1.4
I then use the homebrew tool to symlink all that into /usr/local, so I still have /usr/local/bin/wget and /usr/local/lib/libwget.dylib
Later if I need a different version of wget I can install it in parallel and just change the version that is linked into the /usr/local tree.
6. If I am installing stuff from source on a system that is otherwise managed using packages, what's the cleanest way of doing so?
I believe the Homebrew way is cleanest, so use it or do the equivalent. Install to /usr/local/pkgs/name/version and symlink or hard link the rest in.
Do use /usr/local. Every build tool that exists searches there for dependencies and headers. Your life will be much easier.
7. Assuming I manage to compile something fiddly from source, how can I then package that up so other people don't have to jump through the same hoops? Particularly on OS X....
If it has no dependencies you can tar up the the build directory and give it to someone else who can then do "make install". However you can only do this reliably for the exact same versions of OS X. On Linux it will probably work for similar Linux (eg. Ubuntu) with the same Kernel version and libc minor version.
The reason it is not easy to distribute binaries on Unix is because of binary compatibility. The GNU people, and everyone else change their binary interfaces often.
Basically don't distribute binaries. Things will probably break in very strange ways.
On Mac, the best option is to make a macports package. Everyone uses macports. On Linux there are so many different build systems and combinations, I don't think there is any better advise than to write a blog entry about how you succeeded building x tool in y strange configuration.
If you make a package description (for macports or homebrew) then anyone can install that package, and it solves the dependency problems too. However this is often not easy, and it also isn't easy to get your macports recipe included in the main macports tree. Also macports doesn't support exotic installation types, they offer one choice for all packages.
One of my future goals with Homebrew is to make it possible to click a link on a website (eg. homebrew://blah and it will download that Ruby script, install the deps for that package and then build the app. But yeah, not yet done, but not too tricky considering the design I chose.
8. What are the command line tools I need to master to get good at this stuff? Stuff like otool, pkg-config etc.
otool is really only useful afterwards. It tells you what the built binary links to. When you are figuring out the dependencies of a tool you have to build, it is useless. The same is true of pkg-config as you will have already installed the dependency before you can use it.
My tool chain is, read the README and INSTALL files, and do a configure --help. Watch the build output to check it is sane. Parse any build errors. Maybe in future, ask on serverfault :)
I was able to take @Struder's answer above and mostly make it work, but like @Seth I was getting the "cannot stat sapi/cgi/php-cgi" error.
I ended up making some additional tweaks to the Portfile: Adding enable-fpm only when the fastcgi variant is used, getting rid of the "cannot stat" error, and copying the default php-fpm config file into place. The config file still needs to be user-customized, but this portfile will get you up and running with php5.3.3.
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
# $Id: Portfile 71588 2010-09-17 05:21:24Z ryandesign@macports.org $
PortSystem 1.0
name php5
conflicts php5-devel php52
# Update revision of php5-eaccelerator when updating version of php5
epoch 1
version 5.3.3
revision 2
set major [lindex [split ${version} .] 0]
set my_name php${major}
dist_subdir ${my_name}
categories lang php www
maintainers ryandesign jwa
homepage http://www.php.net/
master_sites php
distname php-${version}
use_bzip2 yes
platforms darwin freebsd
use_parallel_build yes
description \
PHP: Hypertext Preprocessor
long_description \
PHP is a widely-used general-purpose scripting language \
that is especially suited for developing web sites, but can also \
be used for command-line scripting.
checksums \
[suffix ${distname}] \
md5 21ceeeb232813c10283a5ca1b4c87b48 \
sha1 9f66716b341119e4e4f8fe3d81b7d0a5daf3cbc8 \
rmd160 9edb51663feac9b787f8382012893f1ac98fec6a
depends_build \
port:pkgconfig \
port:autoconf213
depends_lib \
path:bin/gsed:gsed \
port:libtool \
port:libxml2 \
port:bzip2 \
port:mhash \
port:pcre \
port:readline \
port:zlib
# Use -p1 to accommodate the Suhosin patch
patch.pre_args -p1
patchfiles patch-scripts-php-config.in.diff \
patch-ext-mysqlnd-mysqlnd.h.diff
use_autoconf yes
autoconf.cmd ${prefix}/bin/autoconf213
set phpinidir ${prefix}/etc/${my_name}
set extraphpinidir ${prefix}/var/db/${my_name}
destroot.keepdirs ${destroot}${extraphpinidir}
configure.args \
--mandir=${prefix}/share/man \
--infodir=${prefix}/share/info \
--with-config-file-path=${phpinidir} \
--with-config-file-scan-dir=${extraphpinidir} \
--disable-all \
--enable-bcmath \
--enable-ctype \
--enable-dom \
--enable-fileinfo \
--enable-filter \
--enable-hash \
--enable-json \
--enable-libxml \
--enable-pdo \
--enable-phar \
--enable-session \
--enable-simplexml \
--enable-tokenizer \
--enable-xml \
--enable-xmlreader \
--enable-xmlwriter \
--with-bz2=${prefix} \
--with-mhash=${prefix} \
--with-pcre-regex=${prefix} \
--with-readline=${prefix} \
--with-libxml-dir=${prefix} \
--with-zlib=${prefix} \
--without-pear \
--disable-cgi
# php5-mysql +mysqlnd needs mysqlnd support compiled into php
configure.env-append PHP_MYSQLND_ENABLED=yes
configure.universal_args-delete --disable-dependency-tracking
platform darwin 10 {
configure.env-append \
LIBS=-lresolv
}
variant no_web conflicts apache apache2 fastcgi description {Don't include any web server support} {}
# Build an Apache 1 module. On Mac OS X, it uses Apple's provided Apache 1 server.
# On other platforms, the MacPorts apache port is used. Keep the options here
# in sync with those in the relevant part of the post-destroot phase.
variant apache conflicts apache2 no_web description {Add Apache 1 web server module} {
if { ! [variant_isset macosx] && (![info exists os.subplatform] || ${os.subplatform} != "macosx") } {
depends_lib-append \
port:apache
configure.args-append \
--with-apxs=${prefix}/sbin/apxs
} else {
destroot.violate_mtree yes
configure.args-append \
--with-apxs=/usr/sbin/apxs
}
}
# Build an Apache 2.2 module. Keep the options here in sync with those in the
# relevant part of the post-destroot phase.
variant apache2 conflicts apache no_web description {Add Apache 2.2 web server module} {
pre-configure {
# Checking for mod_cgi.so is a convenient way to verify apache2 is using its
# +preforkmpm variant. (+eventmpm and +workermpm instead provide mod_cgid.so.)
if {![file exists ${prefix}/apache2/modules/mod_cgi.so]} {
ui_error "To use ${name} with the +apache2 variant, apache2 must be installed with the +preforkmpm variant."
return -code error "incompatible apache2 installation"
}
}
destroot.violate_mtree yes
depends_lib-append \
port:apache2
configure.args-append \
--with-apxs2=${prefix}/apache2/bin/apxs
}
# Build a FastCGI binary. Keep the options here in sync with those in the
# relevant part of the post-destroot phase.
variant fastcgi conflicts no_web description {Add FastCGI web server binary} {
if { ![variant_isset apache] && ![variant_isset apache2] } {
configure.args-delete \
--disable-cgi
configure.args-append \
--enable-fpm \
--enable-cgi
}
}
foreach {old_variant new_port} {
gmp gmp
imap imap
macports_snmp snmp
mssql mssql
mysql4 mysql
mysql5 mysql
mysqlnd mysql
oracle oracle
pcntl pcntl
postgresql82 postgresql
postgresql83 postgresql
pspell pspell
snmp snmp
sockets sockets
sqlite sqlite
tidy tidy
} {
eval [subst {
variant ${old_variant} description "Obsolete; install ${my_name}-${new_port} port instead" {
pre-configure {
ui_msg "The +${old_variant} variant is obsolete. Please install the ${my_name}-${new_port} port instead."
}
}
}]
}
variant ipc description {Add semaphore, shared memory and IPC functions} {
configure.args-append \
--enable-shmop \
--enable-sysvsem \
--enable-sysvshm \
--enable-sysvmsg
}
if {![variant_isset apache] && ![variant_isset apache2] && ![variant_isset fastcgi] && ![variant_isset no_web]} {
default_variants +apache2
}
variant pear description {Add PEAR} {
configure.args-delete \
--without-pear
configure.args-append \
--with-pear=${prefix}/lib/php
destroot.target-append \
install-pear
destroot.args-append \
PHP_PEAR_INSTALL_DIR=${prefix}/lib/php
post-destroot {
#nuke pear-stuff in ${destroot}
system "cd ${destroot} && rm -rf .channels .depdb .depdblock .filemap .lock"
system "if \[ -f ${prefix}/lib/php/.depdblock \]; then rm -f ${destroot}${prefix}/lib/php/.depdblock; fi"
system "if \[ -f ${prefix}/lib/php/.depdb \]; then rm -f ${destroot}${prefix}/lib/php/.depdb; fi"
system "if \[ -f ${prefix}/lib/php/.filemap \]; then rm -f ${destroot}${prefix}/lib/php/.filemap; fi"
system "if \[ -f ${prefix}/lib/php/.lock \]; then rm -f ${destroot}${prefix}/lib/php/.lock; fi"
system "if \[ -d ${prefix}/lib/php/.channels \]; then rm -rf ${destroot}${prefix}/lib/php/.channels; fi"
}
}
variant suhosin description {Add Suhosin patch} {
pre-fetch {
if {"darwin" == ${os.platform} && ${os.major} < 9} {
ui_error "The suhosin variant requires Mac OS X 10.5 or greater."
return -code error "incompatible Mac OS X version"
}
}
set suhosin_patch_version ${version}-0.9.10
set suhosin_patch suhosin-patch-${suhosin_patch_version}.patch.gz
patch_sites-append http://download.suhosin.org/
patchfiles-append ${suhosin_patch}
checksums-append \
${suhosin_patch} \
md5 b66b27c43b1332400ef8982944c3b95b \
sha1 76675242cfdeff763767900213346af622002490 \
rmd160 8dcd8b51ea0357b6cc51e70e495e18f341c62f7c
}
destroot.args \
INSTALL_ROOT=${destroot}
destroot.target \
install-cli install-build install-headers install-programs
post-destroot {
# Copy the Apache 1 module.
if { [variant_isset apache] } {
xinstall -m 755 -d ${destroot}${prefix}/libexec/apache \
${destroot}${prefix}/etc/apache/extra
xinstall -m 755 ${worksrcpath}/libs/libphp5.so ${destroot}${prefix}/libexec/apache/
xinstall -m 755 -c ${filespath}/mod_php.conf ${destroot}$prefix/etc/apache/extra
}
# Copy the Apache 2.2 module.
if { [variant_isset apache2] } {
xinstall -m 755 -d ${destroot}${prefix}/apache2/modules \
${destroot}${prefix}/apache2/conf/extra
xinstall -m 755 ${worksrcpath}/libs/libphp5.so ${destroot}${prefix}/apache2/modules/
xinstall -m 755 -c ${filespath}/mod_php.conf ${destroot}${prefix}/apache2/conf/extra
}
if { [variant_isset fastcgi] } {
# If we've built an Apache module (any version) then the FastCGI binary
# will not have been built, so we need to run through the whole process
# again and build just the FastCGI binary. Keep the options here in sync
# with the options specified in the apache and apache2 variants.
if { [variant_isset apache] } {
if { ![variant_isset macosx] && (![info exists os.subplatform] || ${os.subplatform} != "macosx") } {
configure.args-delete \
--with-apxs=${prefix}/sbin/apxs
} else {
configure.args-delete \
--with-apxs=/usr/sbin/apxs
}
}
if { [variant_isset apache2] } {
configure.args-delete \
--with-apxs2=${prefix}/apache2/bin/apxs
}
# Run the build again to get the FastCGI binary. Keep the options here
# in sync with those in the fastcgi variant.
if { [variant_isset apache] || [variant_isset apache2] } {
configure.args-delete \
--disable-cgi
configure.args-append \
--enable-fpm \
--enable-cgi
ui_msg "$UI_PREFIX Configuring ${name} again for fastcgi"
command_exec configure
ui_msg "$UI_PREFIX Building ${name} again for fastcgi"
command_exec build
ui_msg "$UI_PREFIX Staging ${name} fastcgi into destroot"
}
# Copy the FastCGI binary to the bin dir under a new name so it doesn't
# conflict with the cli version.
if {[file exists ${worksrcpath}/sapi/cgi/php-cgi]} {
xinstall -m 755 ${worksrcpath}/sapi/cgi/php-cgi ${destroot}${prefix}/bin
}
# Copy the default FastCGI config
xinstall -m 644 ${worksrcpath}/sapi/fpm/php-fpm.conf ${destroot}${prefix}/etc/
}
#file rename ${destroot}${prefix}/etc/pear.conf ${destroot}${prefix}/etc/pear.conf.sample
# Copy the default php.ini files.
xinstall -m 755 -d ${destroot}${phpinidir}
xinstall -m 644 -W ${worksrcpath} \
php.ini-development \
php.ini-production \
${destroot}${phpinidir}
# Copy mysqlnd headers.
xinstall -d ${destroot}${prefix}/include/php/ext/mysqlnd
eval xinstall -m 644 [glob ${worksrcpath}/ext/mysqlnd/*.h] ${destroot}${prefix}/include/php/ext/mysqlnd
}
pre-activate {
set filepath ${extraphpinidir}/.turd_${name}
if {[file exists ${filepath}]} {
delete ${filepath}
}
}
post-activate {
if {[file exists ${prefix}/etc/php.ini] && ![file exists ${phpinidir}/php.ini]} {
move ${prefix}/etc/php.ini ${phpinidir}
ui_msg "Your ${prefix}/etc/php.ini has been moved to ${phpinidir}/php.ini"
ui_msg ""
}
if {![file exists ${phpinidir}/php.ini]} {
ui_msg "To customize php, copy"
ui_msg "${phpinidir}/php.ini-development (if this is a development server) or"
ui_msg "${phpinidir}/php.ini-production (if this is a production server) to"
ui_msg "${phpinidir}/php.ini and then make changes."
} else {
ui_msg "You may need to update your php.ini for any changes that have been made"
ui_msg "in this version of php. Compare ${phpinidir}/php.ini with"
ui_msg "${phpinidir}/php.ini-development (if this is a development server) or"
ui_msg "${phpinidir}/php.ini-production (if this is a production server)."
}
if {![variant_isset no_web]} {
ui_msg ""
ui_msg "If this is your first install, you need to activate PHP in your web server."
if {![variant_isset fastcgi]} {
if {[variant_isset apache]} {
set moduledir ${prefix}/libexec/modules
set apxs ${prefix}/apache/bin/apxs
}
if {[variant_isset apache2]} {
set moduledir ${prefix}/apache2/modules
set apxs ${prefix}/apache2/bin/apxs
}
ui_msg ""
ui_msg "To enable PHP in Apache, run"
ui_msg " cd ${moduledir}"
ui_msg " ${apxs} -a -e -n \"${my_name}\" lib${my_name}.so"
}
}
#ui_msg "* copy ${prefix}/etc/pear.conf.sample to ${prefix}/etc/pear.conf"
}
variant debug description {Enable debug support (useful to analyze a PHP-related core dump)} {
configure.args-append --enable-debug
}
test.run yes
livecheck.type regex
livecheck.url ${homepage}downloads.php
livecheck.regex get/php-(5\\.\[0-9.\]+)\\.tar
Best Answer
The old version of your software is likely still around. Check this by running:
where PACKAGE is what you want to downgrade. This will list out the "fully-qualified" name of the ports that match. You'll see the active port and the old, inactive port. You can switch them by doing something akin to this procedure: