I am developing hobby OS which is cross-compiled to other architecture than my development PC and is run in QEMU emulator.
I am trying to introduce unit testing of the source files I develop for my kernel but to let them run on my development machine rather than in QEMU on my target.
In order to cross-compile my sources, I use the toolchain file which uses my custom GCC toolchain. As coming from CMake principle of toolchain file usage, the toolchain file is set up prior to project(...) definition in my root CMakeLists.txt file.
My question is how to build my test executables for my dev machine (x86_64) using the built-in GCC while cross-compiling my kernel binary for target platform... I do not know how to set CMAKE_CXX_COMPILER / CMAKE_C_COMPILER cmake variables specifically for each use case (testing, target build)
To have a look at my particular project, please feel free to navigate here:https://gitlab.com/revolta/revolta
I would like to add test/ to my project root including selected sources from source/... and manage it somehow from my root CMakeLists.txt
Thanks in advance for any concept ideas and help! Cheers Martin
The rule is - there is one compiler per configuration. Do not try to make to use two compilers per configuration. Instead run cmake two times and configure it twice,. separately for x86 testing and separately for releasing to target build.
So write a small script (you have configure.sh anyway) (I usually write a makefile with all PHONY targets) that would run and build the project twice for two configurations:
# ./compile_and_test_your_project.sh
# build for target host
cmake -DCMAKE_TOOLCHAIN_FILE=the_toolchain -S. -B_build/crosscompiled
cmake --build _build/crosscompiled --target the_main_project_target
( cd _build/crosscompiled && ctest )
# build for native host
cmake -DCMAKE_C_FLAGS="-fsanitize=undefined -ggdb3 -O0" -S. -B_build/native
cmake --build _build/native --target only_testing_targets
( cd _build/native && ctest )
Do not set CMAKE_CROSSCOMPILING_EMULATOR inside cmake config. I advise to try to keep cmake configuration platform agnostic as much as you can and pass platform specific parts using arguments to cofiguration cmake. Such way is scalable - you may use a different toolchain and different environment with ease, or try different compiler options. Inside cmake you can see if you are crosscompiling with just if (CMAKE_CROSSCOMPILING). Also see CMAKE_CROSSCOMPILING_EMULATOR.
ps. My makefile from one of my projects that sets different CMAKE_CROSSCOMPILING_EMULATOR depending on make target.
I have a cmake project that successfully builds locally but errors with
include could not find load file:
CmakeDependentOption
when trying to build on a CI platform or in Docker. Note that CMakeDependentOption.cmake is a script that comes with cmake itself. So it should just be available. On CI to install cmake, I wget the relevant cmake release from their downloads page, unzip it and add the bin directory to the PATH environment variable. Then I use the cmake command to build my library. The result is the above error.
I suspect this means that a CMake variable (such as "CMAKE_MODULE_PATH" but not, since this variable seems to be empty at the start of the cmake script) is messed up or not set somehow. The path to the correct file to include is
<cmake_root>/share/cmake-3.18/Modules/CMakeDependentOption.cmake
And I have verified that it exists manually. My question: is there a way to locate this directory from within cmake? Perhaps a cmake --config or cmake --libs mode (a bit like pkg-config?)
Failing that, does anybody have any suggestions as to why this is happening and how to get around it.
You can locally because most likely you don't use a linux based platform, like windows or mac. This is because linux filesystem are case sensitive. Which means CmakeDependentOption is different from CMakeDependentOption.
Docker runs containers in linux, so filenames are gonna be case sensitive, and the include is going to fail if the cases are different.
I've installed a version of CMake to /some/where/cmake, and have put /some/where/cmake/bin in the PATH.
What environment variables do I need to set, and what other actions do I need to take, in order for my custom CMake to function properly? Specifically, how do I ensure it looks in /some/where/cmake/share before /usr/share for CMake-related files?
Notes:
The OS is GNU/Linux.
I'm using CMake 3.16.6.
If I issue the CMake command message(STATUS ${CMAKE_ROOT}), I get: /some/where/cmake/share/cmake-3.16
What environment variables do I need to set, and what other actions do I need to take, in order for my custom CMake to function properly? Specifically, how do I ensure it looks in /some/where/cmake/share before /usr/share for CMake-related files?
Nothing! CMake is designed to look relative to the binary's actual location on your filesystem and otherwise ignore standard system directories for its own functioning (of course it will detect these for toolchain purposes).
I have personally installed CMake 3.1 -- 3.20 on Ubuntu Linux by just downloading and untarring the release archives here to /home/alex/bin/cmake-3.X.Y and creating corresponding symlinks cmake-3.X, ctest-3.X, and cpack-3.X in /home/alex/bin (which is in my PATH). I use these regularly to test answers I post here on StackOverflow. Took all of 5 minutes to set up.
I am attempting to get cross-compiling for Raspberry Pi working on my Ubuntu machine.
During my initial attempts I was using the arm-linux-gnueabi compiler, which is available in the Ubuntu repo. I got this working. I was able to build all my dependencies and use the cross-compiler in my cmake project.
However, I believe I should be using the hf version, so I switched to arm-linux-gnueabihf. Then I realized that this does not work with Raspberry Pi since it is armv6.
After some Googling, I then found the pre-built toolchain from GitHub.
I downloaded the toolchain, but I don't really understand how to "install" it. I extracted the files to my home directory. The directory structure looks like this:
/gcc-linearo-arm-linux-gnueabihf-raspbian
/arm-linux-gnueabihf
/bin
(contains g++, gcc, etc)
/lib
(contains libstdc++ library)
/bin
(contains arm-linux-gnueabihf-g++, arm-linux-gnueabihf-...)
/lib
(gcc lib stuff)
If I change directory to the INNER bin folder I am able to compile a test program from the terminal without any problems.
~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/
arm-linux-gnueabihf/bin$ g++ test.cpp -o test
I then tried to compile a test program in the OUTER bin folder, which contains the prefixed versions of the tools.
~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin$
arm-linux-gnueabihf-g++ test.cpp -o test
However, when I try to use the compiler now (from outside the inner bin directory), it is unable to find the libstdc++ shared library that comes with the toolchain:
arm-linux-gnueabihf-gcc: error while loading shared libraries:
libstdc++.so.6: cannot open shared object file: No such file or directory.
Furthermore, I want to be able to use the compiler without having to navigate to the bin directory. So I tried adding the OUTER bin directory (since I want the prefixed versions) and both lib directories to my PATH:
export PATH=$PATH:~/tools/.../bin
export PATH=$PATH:~/tools/.../lib
export PATH=$PATH:~/tools/.../.../lib
However, this results in the same error. How should I "install" the toolchain so that I can use the toolchain from everywhere, just like I can when I use the cross-compilers from the Ubuntu repo?
I'm gonna try to write this as a tutorial for you so it becomes easy to follow.
NOTE:
This tutorial only works for older raspbian images. For the newer Raspbian based on Debian Buster see the following how-to in this thread: https://stackoverflow.com/a/58559140/869402
Pre-requirements
Before you start you need to make sure the following is installed:
apt-get install git rsync cmake libc6-i386 lib32z1 lib32stdc++6
Let's cross compile a Pie!
Start with making a folder in your home directory called raspberrypi.
Go in to this folder and pull down the ENTIRE tools folder you mentioned above:
git clone git://github.com/raspberrypi/tools.git
You wanted to use the following of the 3 ones, gcc-linaro-arm-linux-gnueabihf-raspbian, if I did not read wrong.
Go into your home directory and add:
export PATH=$PATH:$HOME/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin
to the end of the file named ~/.bashrc
Now you can either log out and log back in (i.e. restart your terminal session), or run . ~/.bashrc in your terminal to pick up the PATH addition in your current terminal session.
Now, verify that you can access the compiler arm-linux-gnueabihf-gcc -v. You should get something like this:
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabihf-gcc
COLLECT_LTO_WRAPPER=/home/tudhalyas/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/../libexec/gcc/arm-linux-gnueabihf/4.7.2/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: /cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.b
uild/src/gcc-linaro-4.7-2012.08/configure --build=i686-build_pc-linux-gnu --host=i686-build_pc-
linux-gnu --target=arm-linux-gnueabihf --prefix=/cbuild/slaves/oort61/crosstool-ng/builds/arm-l
inux-gnueabihf-raspbian-linux/install --with-sysroot=/cbuild/slaves/oort61/crosstool-ng/builds/
arm-linux-gnueabihf-raspbian-linux/install/arm-linux-gnueabihf/libc --enable-languages=c,c++,fo
rtran --disable-multilib --with-arch=armv6 --with-tune=arm1176jz-s --with-fpu=vfp --with-float=
hard --with-pkgversion='crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08' --with-bugurl=
https://bugs.launchpad.net/gcc-linaro --enable-__cxa_atexit --enable-libmudflap --enable-libgom
p --enable-libssp --with-gmp=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-rasp
bian-linux/.build/arm-linux-gnueabihf/build/static --with-mpfr=/cbuild/slaves/oort61/crosstool-
ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-mpc
=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-
gnueabihf/build/static --with-ppl=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf
-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-cloog=/cbuild/slaves/oort61/cros
stool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --wi
th-libelf=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/a
rm-linux-gnueabihf/build/static --with-host-libstdcxx='-L/cbuild/slaves/oort61/crosstool-ng/bui
lds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static/lib -lpwl' --ena
ble-threads=posix --disable-libstdcxx-pch --enable-linker-build-id --enable-plugin --enable-gol
d --with-local-prefix=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-li
nux/install/arm-linux-gnueabihf/libc --enable-c99 --enable-long-long
Thread model: posix
gcc version 4.7.2 20120731 (prerelease) (crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08
)
But hey! I did that and the libs still don't work!
We're not done yet! So far, we've only done the basics.
In your raspberrypi folder, make a folder called rootfs.
Now you need to copy the entire /liband /usr directory to this newly created folder. I usually bring the rpi image up and copy it via rsync:
rsync -rl --delete-after --safe-links pi#192.168.1.PI:/{lib,usr} $HOME/raspberrypi/rootfs
where 192.168.1.PI is replaced by the IP of your Raspberry Pi.
Now, we need to write a cmake config file. Open ~/home/raspberrypi/pi.cmake in your favorite editor and insert the following:
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)
SET(CMAKE_C_COMPILER $ENV{HOME}/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER $ENV{HOME}/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++)
SET(CMAKE_FIND_ROOT_PATH $ENV{HOME}/raspberrypi/rootfs)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Now you should be able to compile your cmake programs simply by adding this extra flag: -D CMAKE_TOOLCHAIN_FILE=$HOME/raspberrypi/pi.cmake.
Using a cmake hello world example:
git clone https://github.com/jameskbride/cmake-hello-world.git
cd cmake-hello-world
mkdir build
cd build
cmake -D CMAKE_TOOLCHAIN_FILE=$HOME/raspberrypi/pi.cmake ../
make
scp CMakeHelloWorld pi#192.168.1.PI:/home/pi/
ssh pi#192.168.1.PI ./CMakeHelloWorld
Building for newer Raspbian Debian Buster images and ARMv6
The answer by #Stenyg only works for older Raspbian images. The recently released Raspbian based on Debian Buster requires an updated toolchain:
In Debian Buster the gcc compiler and glibc was updated to version 8.3. The toolchain in git://github.com/raspberrypi/tools.git is still based on the older gcc 6 version. This means that using git://github.com/raspberrypi/tools.git will lead to many compile errors.
This tutorial is based on #Stenyg answer. In addition to many other solutions in the internet, this tutorial also supports older Rasperry Pi (A, B, B+, Zero) based on the ARMv6 CPU.
See also:
GCC 8 Cross Compiler outputs ARMv7 executable instead of ARMv6
Set up the toolchain
There is no official git repository containing an updated toolchain (See https://github.com/raspberrypi/tools/issues/102).
I created a new github repository which includes building and precompiled toolchains for ARMv6 based on GCC8 and newer:
https://github.com/Pro/raspi-toolchain
As mentioned in the project's readme, these are the steps to get the toolchain. You can also build it yourself (see the README for further details).
Download the toolchain:
wget https://github.com/Pro/raspi-toolchain/releases/latest/download/raspi-toolchain.tar.gz
Extract it. Note: The toolchain has to be in /opt/cross-pi-gcc since it's not location independent.
sudo tar xfz raspi-toolchain.tar.gz --strip-components=1 -C /opt
You are done! The toolchain is now in /opt/cross-pi-gcc
Optional, add the toolchain to your path, by adding:
export PATH=$PATH:/opt/cross-pi-gcc/bin
to the end of the file named ~/.bashrc
Now you can either log out and log back in (i.e. restart your terminal session), or run . ~/.bashrc in your terminal to pick up the PATH addition in your current terminal session.
Get the libraries from the Raspberry PI
To cross-compile for your own Raspberry Pi, which may have some custom libraries installed, you need to get these libraries onto your host.
Create a folder $HOME/raspberrypi.
In your raspberrypi folder, make a folder called rootfs.
Now you need to copy the entire /liband /usr directory to this newly created folder. I usually bring the rpi image up and copy it via rsync:
rsync -vR --progress -rl --delete-after --safe-links pi#192.168.1.PI:/{lib,usr,opt/vc/lib} $HOME/raspberrypi/rootfs
where 192.168.1.PI is replaced by the IP of your Raspberry Pi.
Use CMake to compile your project
To tell CMake to take your own toolchain, you need to have a toolchain file which initializes the compiler settings.
Get this toolchain file from here:
https://github.com/Pro/raspi-toolchain/blob/master/Toolchain-rpi.cmake
Now you should be able to compile your cmake programs simply by adding this extra flag: -D CMAKE_TOOLCHAIN_FILE=$HOME/raspberrypi/pi.cmake and setting the correct environment variables:
export RASPBIAN_ROOTFS=$HOME/raspberry/rootfs
export PATH=/opt/cross-pi-gcc/bin:$PATH
export RASPBERRY_VERSION=1
cmake -DCMAKE_TOOLCHAIN_FILE=$HOME/raspberry/Toolchain-rpi.cmake ..
An example hello world is shown here:
https://github.com/Pro/raspi-toolchain/blob/master/build_hello_world.sh
I couldn't get the compiler (x64 version) to use the sysroot until I added SET(CMAKE_SYSROOT $ENV{HOME}/raspberrypi/rootfs) to pi.cmake.
You may use clang as well. It used to be faster than GCC, and now it is quite a stable thing. It is much easier to build clang from sources (you can really drink cup of coffee during build process).
In short:
Get clang binaries (sudo apt-get install clang).. or download and
build (read instructions here)
Mount your raspberry rootfs (it
may be the real rootfs mounted via sshfs, or an image).
Compile your code:
path/to/clang --target=arm-linux-gnueabihf --sysroot=/some/path/arm-linux-gnueabihf/sysroot my-happy-program.c -fuse-ld=lld
Optionally you may use legacy arm-linux-gnueabihf binutils. Then you may remove "-fuse-ld=lld" flag at the end.
Below is my cmake toolchain file.
toolchain.cmake
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# Custom toolchain-specific definitions for your project
set(PLATFORM_ARM "1")
set(PLATFORM_COMPILE_DEFS "COMPILE_GLES")
# There we go!
# Below, we specify toolchain itself!
set(TARGET_TRIPLE arm-linux-gnueabihf)
# Specify your target rootfs mount point on your compiler host machine
set(TARGET_ROOTFS /Volumes/rootfs-${TARGET_TRIPLE})
# Specify clang paths
set(LLVM_DIR /Users/stepan/projects/shared/toolchains/llvm-7.0.darwin-release-x86_64/install)
set(CLANG ${LLVM_DIR}/bin/clang)
set(CLANGXX ${LLVM_DIR}/bin/clang++)
# Specify compiler (which is clang)
set(CMAKE_C_COMPILER ${CLANG})
set(CMAKE_CXX_COMPILER ${CLANGXX})
# Specify binutils
set (CMAKE_AR "${LLVM_DIR}/bin/llvm-ar" CACHE FILEPATH "Archiver")
set (CMAKE_LINKER "${LLVM_DIR}/bin/llvm-ld" CACHE FILEPATH "Linker")
set (CMAKE_NM "${LLVM_DIR}/bin/llvm-nm" CACHE FILEPATH "NM")
set (CMAKE_OBJDUMP "${LLVM_DIR}/bin/llvm-objdump" CACHE FILEPATH "Objdump")
set (CMAKE_RANLIB "${LLVM_DIR}/bin/llvm-ranlib" CACHE FILEPATH "ranlib")
# You may use legacy binutils though.
#set(BINUTILS /usr/local/Cellar/arm-linux-gnueabihf-binutils/2.31.1)
#set (CMAKE_AR "${BINUTILS}/bin/${TARGET_TRIPLE}-ar" CACHE FILEPATH "Archiver")
#set (CMAKE_LINKER "${BINUTILS}/bin/${TARGET_TRIPLE}-ld" CACHE FILEPATH "Linker")
#set (CMAKE_NM "${BINUTILS}/bin/${TARGET_TRIPLE}-nm" CACHE FILEPATH "NM")
#set (CMAKE_OBJDUMP "${BINUTILS}/bin/${TARGET_TRIPLE}-objdump" CACHE FILEPATH "Objdump")
#set (CMAKE_RANLIB "${BINUTILS}/bin/${TARGET_TRIPLE}-ranlib" CACHE FILEPATH "ranlib")
# Specify sysroot (almost same as rootfs)
set(CMAKE_SYSROOT ${TARGET_ROOTFS})
set(CMAKE_FIND_ROOT_PATH ${TARGET_ROOTFS})
# Specify lookup methods for cmake
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# Sometimes you also need this:
# set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# Specify raspberry triple
set(CROSS_FLAGS "--target=${TARGET_TRIPLE}")
# Specify other raspberry related flags
set(RASP_FLAGS "-D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS")
# Gather and distribute flags specified at prev steps.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CROSS_FLAGS} ${RASP_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CROSS_FLAGS} ${RASP_FLAGS}")
# Use clang linker. Why?
# Well, you may install custom arm-linux-gnueabihf binutils,
# but then, you also need to recompile clang, with customized triple;
# otherwise clang will try to use host 'ld' for linking,
# so... use clang linker.
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld)
For Windows host, I want to highly recommend this tutorial::
Download and install the toolchain
Sync sysroot with your RPi include/lib directories
Compile your code
Drag and drop the executable to your RPi using SmarTTY
Run it!
Nothing more, nothing less!
Prebuilt GNU Toolchains available for Raspberry, Beaglebone, Cubieboard, AVR (Atmel) and more
I could not compile QT5 with any of the (fairly outdated) toolchains from git://github.com/raspberrypi/tools.git. The configure script kept failing with an "could not determine architecture" error and with massive path problems for include directories. What worked for me was using the Linaro toolchain
http://releases.linaro.org/components/toolchain/binaries/4.9-2016.02/arm-linux-gnueabihf/runtime-linaro-gcc4.9-2016.02-arm-linux-gnueabihf.tar.xz
in combination with
https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py
Failing to fix the symlinks of the sysroot leads to undefined symbol errors as described here: An error building Qt libraries for the raspberry pi
This happened to me when I tried the fixQualifiedLibraryPaths script from tools.git. Everthing else is described in detail in http://wiki.qt.io/RaspberryPi2EGLFS . My configure settings were:
./configure -opengl es2 -device linux-rpi3-g++ -device-option CROSS_COMPILE=/usr/local/rasp/gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -sysroot /usr/local/rasp/sysroot -opensource -confirm-license -optimized-qmake -reduce-exports -release -make libs -prefix /usr/local/qt5pi -hostprefix /usr/local/qt5pi
with /usr/local/rasp/sysroot being the path of my local Raspberry Pi 3 Raspbian (Jessie) system copy and /usr/local/qt5pi being the path of the cross compiled QT that also has to be copied to the device. Be aware that Jessie comes with GCC 4.9.2 when you choose your toolchain.
The initial question has been posted quite some time ago and in the meantime Debian has made huge headway in the area of multiarch support.
Multiarch is a great achievement for cross compilation!
In a nutshell the following steps are required to leverage multiarch for Raspbian Jessie cross compilation:
On your Ubuntu host install Debian Jessie amd64 within a chroot or a LXC container.
Enable the foreign architecture armhf.
Install the cross compiler from the emdebian tools repository.
Tweak the cross compiler (it would generate code for ARMv7-A by default) by writing a custom gcc specs file.
Install armhf libraries (libstdc++ etc.) from the Raspbian repository.
Build your source code.
Since this is a lot of work I have automated the above setup. You can read about it here:
Cross Compiling for Raspbian
there is a CDP Studio IDE available that makes cross compile and deploy quite simple from both windows and linux and you can just check the raspberry toolchain checkbox during the installation.
(PS. it has GPIO and I2C support so no code is needed to access those)
The IDE demo of raspberry use is up here:
https://youtu.be/4SVZ68sQz5U
and you can download the IDE here: https://cdpstudio.com/home-edition
I have created an example repository which shows how to cross-compile for a Raspberry Pi 4 using CMake. It also includes the installation of the toolchain and some special steps necessary when cloning the root filesystem. It should in principle be possible to use it for older Pis as well, but the toolchain might be a different one: https://github.com/spacefisch/raspberrypi-crosscompiling
Summary
I want to run my cross-compiled application against the 10.5 libraries. Is there an environmental variable that allows this to work?
Longer version
I cross-compiled my OS X C++ application for a 10.5 target, on a 10.6 host. It compiles fine. The compiled application is linked against libraries like /usr/lib/libstdc++.6.dylib. When I run it on my system, it will use the 'host' version of libraries, which are 10.6. I'd like to test it against the 10.5 versions, which are all contained in the `/Developer/SDKs/MacOSX10.5.sdk directory. How do I do this?
I tried various flavours of DYLD_LIBRARY_PATH, DYLD_ROOT_PATH, etc, as documented in the manual, but I haven't managed to get it working.
Use install_name_tool to change the path. You may not be able to squeeze in a longer path if the linker didn't add padding, but you can use an rpath instead. For example, I changing the load path for an app on my system to use the 10.5 SDK by doing:
install_name_tool -change /usr/lib/libstdc++.6.dylib #rpath/libstdc++.6.dylib /path/to/executable
install_name_tool -add_rpath /Developer/SDKs/MacOSX10.5.sdk/usr/lib /path/to/executable
and it ran fine after the fact. I wouldn't want to make any assurances, but assuming you compiled against the 10.5 SDK initially, you've got a shot.
If you need to see the paths the executable is using, otool -L will list them.
It is unlikely that this is possible, given that OS X does not have a stable kernel ABI. Instead, the stable ABI is the one provided by the system libraries. Therefore, using system libraries of a different version than the kernel may break. (I do not know to what degree it breaks.)
See http://developer.apple.com/library/mac/#qa/qa2001/qa1118.html
Try this:
Open your project in Xcode.
Under Executables in the Groups & Files column, right-click on your application's executable and select Get Info
Select the Arguments tab
In the bottom half of the window, under "Variables to be set in the environment:", click the + button.
In the row that shows up in the table, enter DYLD_LIBRARY_PATH under Name, and enter the path (e.g. /Developer/SDKs/MacOSX10.5.sdk/usr/lib) under Value.
Now you've got your link path environment variable set up. This environment variable will be set for you when you run that executable from within Xcode. To test your app, just go to the Run menu and select "Run". If you run the app by double-clicking it directly in the Finder, you won't get this environment variable set for you. The setting only takes effect when you run from Xcode.
Here's Apple's documentation on this process:
http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/XcodeProjectManagement/230-Defining_Executable_Environments/executable_environments.html