How to force Boost to use rpath? - boost

I have to build Boost outside the "usual" directory tree (i.e., /custom/dir instead of /usr), which is not that much of a problem: Just pass --prefix=/custom/path to ./runscript.sh / ./bjam, and there you go.
Or so I thought.
The problem is that some of the Boost libraries depend on each other, and - using the default build process going through ./bootstrap.sh / ./bjam - it seems that the --prefix path is not added to the library search path for the Boost libs, i.e. no -Wl,-rpath is applied. That means that Boost libraries depending on other Boost libraries cannot find those at runtime.
My application - linking those /custom/path Boost libraries - already fails at ./configure stage because libboost_filesystem.so cannot find libboost_system.so, even though I passed -Wl,-rpath=/custom/path/boost/lib to my own compiler line (i.e. the correct path to the Boost libs, I double-checked that libboost_system.so is there).
Now, to avoid heavy-handed methods like setting LD_LIBRARY_PATH, I'd like to build Boost in a way so that all the Boost libraries have the proper search path for the other Boost libs compiled into them. However, I was unable to find the proper procedure for that. Can anybody help me?

I needed to do this recently for another project, although I needed to use $ORIGIN to make the path relative to the location of boost's shared objects.
This required the following on a bash command line:
./b2 hardcode-dll-paths=true dll-path="'\$ORIGIN/../lib'" --prefix=$MY_PREFIX install
Figuring out the magic collection of characters to get that $ORIGIN placed correctly in the shared object took a bit of trial and error, so I hope writing the answer here helps others to avoid fumbling around with this.

You can add compiler & link options during build from the command line with:
bjam hard-code-dll-path=true dll-path=/custom/path
There's a FAQ item in the Boost Build docs about this (see B2 docs).

Related

Finding vcpkg packages that don't have `find_package` documentation

When you install many packages through vcpkg (such as vcpkg install cairo), at the end of this process, you are told what find_package and target_link_libraries CMake commands to use in order to link to the package that was installed. And this works fine; you can even re-execute the install command to see these CMake commands again.
However, some packages installed through vcpkg don't have these. After installing Pango for example, there is no list of CMake commands to actually use the library. I found the target CMake file for find_package in several of the vcpkg package directories, but the Pango directory has no CMake file for the package.
For some reason, example code using Pango can still compile (ie: it can find Pango's headers), but it fails to link due to not linking to the right libraries.
So how is this supposed to work? Do I have to list the include directories, library directories, and library files through a variety of CMake interfaces for Pango? Or is there some alternative inclusion mechanism that takes care of the details like most other vcpkg packages?
Note that I'm using Visual Studio 2019's built-in CMake functionality to try to build with these.
find_package finds a particular kind of .cmake file that is usually shipped with vcpkg packages. These .cmake files do the work of setting include directories and libraries to link with.
As such, if a vcpkg package does not include such a file, you will need to essentially do the work that the file would have done. Fortunately, CMake and vcpkg know where the headers and library build files are for the various configurations. What you need to do is find those directories and libraries, then add them to your project (along with any other special compiler options that the package requires, which requires some familiarity with the package).
To find the include directory containing a library's header, use find_path to set a variable, giving it the name of a header file to search for. For example:
find_path(PANGO_INCLUDE_DIR pango/pango.h)
This header directory can then be set as part of the include path:
target_include_directories(project_name_here PRIVATE ${PANGO_INCLUDE_DIR})
Libraries are a bit harder, since you have to track down the full name (minus extensions) of the actual library. And if the package involves multiple libraries, you need to track down all of those which are applicable to you.
Given the name of a library or libraries of interest, you can find them one at a time with find_library, setting those libraries into variables:
find_library(PANGO_LIBRARY pango-1.0)
find_library(PANGOCAIRO_LIBRARY pangocairo-1.0)
You can then link with those libraries via target_link_libraries:
target_link_libraries(cairo_vcpkg PRIVATE
...
${PANGO_LIBRARY}
${PANGOCAIRO_LIBRARY}
)
Indeed, some packages installed via vcpkg do not export a .cmake file like Pango for you and SDL for me.
I want to clarify that I have been trying to use vcpkg for two days, I share with you the cmakelist.txt that I use on my side so that SDL works as if I had used find_package (SDL Required)
cmake_minimum_required(VERSION 3.16)
project(xxxx)
### Specify the C++ standard ###
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake)
### To find and use SDL ###
# find path of include and lib
find_path(SDL_INCLUDE_DIR SDL/SDL.h)
find_library(SDL_LIBRARY SDL)
# find pat of manual-link library
set (LIBRARIES_TO_LINK C:/dev/vcpkg/installed:/x64-windows/lib/manual-link)
find_library(SDL1_TEST SDLmain HINTS ${LIBRARIES_TO_LINK})
....

Boost installation error: No toolsets were configured

I've been trying this for over 5 days and I have no idea how to get this to work. I had successfully installed boost once, then I got my computer re-imaged and now it's just not happening. I have Windows 7 Enterprise, and 64-bit operating system.
I downloaded boost from here sourceforge
unzipped it into program files.
I then went to the VS 2013 Native Command prompt. Changed directory to boost tools/build
Ran bootstrap.bat
I then ran ./b2 address-model=64
but it did not give me directories for the compiler and the linker like last time.
I then ran ./b2 --prefix=C:\ProgramFiles\boost_1_58_0
but again nothing happens. I get the following errors:
Warning: No Toolsets were configured.
Warning: Configuring default toolset ""msvc"
Warning: If the default is wrong, your build may not work correctly
warning: Use the "toolset=xxxxx" option to overrride out guess
warning: for more configuration please consult
I have no idea why this worked the first time I had done this and why this isn't working now. Can someone please help me out. I know nothing about Unix but I need to install this so I can use the libraries.
I compile boost with both mingw (64 bit) and msvc 2013 pro. I have never in my life used the vs command prompt to build boost with msvc. Here are my commands to build 64 bit binaries on both toolchains.
First go into the boost folder and just double click bootstrap.bat. This should run and build bjam/b2. Nothing special required and doesn't matter what compiler this gets built with.
Then simply run, in a normal command prompt:
bjam.exe -a -j8 --toolset=msvc --layout=system optimization=speed link=shared threading=multi address-model=64 --stagedir=stage\MSVC-X64 release stage
Where -a forces rebuild all, -j8 means for the build to use 8 cores (adjust this based on your processor capabilities), toolset is obvious, layout means how to structure the naming of the output files, address-model is obvious, stagedir is where to output the built binaries (either relative or absolute path) and release stage is the type of build the system. See more here.
Same thing but using 64 bit mingw.
bjam.exe -j8 --toolset=gcc --layout=system optimization=speed link=shared threading=multi address-model=64 --stagedir=stage\x64 release stage
You can even go on to build additional libraries with a second pass tweaking your arguments. For example, after I've built the core libs with the above command, I run the following command to build in zlib and gzip support.
bjam.exe -a -j8 --toolset=msvc --layout=system optimization=speed link=shared threading=multi address-model=64 --stagedir=stage\MSVC-X64 --with-iostreams -s BZIP2_SOURCE=C:\dev\libraries\cpp\bzip2-1.0.6 -s ZLIB_SOURCE=C:\dev\libraries\cpp\zlib-1.2.8 release stage
Anyway that's just as an example. I linked to the full docs for the build system. Try building using these commands NOT inside a vs command prompt. If you still have problems then please post specific errors.
A note about MSVC
So, msvc compiler + boost supports a type of linking where it will automatically include additional libraries that it knows it needs. I believe boost does this by using the #pragma directive in headers. For example you might use boost::asio configured in such a way that it needs boost::system (for error codes and such). Even if you don't explicitly add boost::system library to the linker options, msvc will "figure out" that it needs this library and automatically try to link against it.
Now an issue arises here because you're using layout=system. The libraries are named simply "boost_" + the lib name, like "boost_system.dll". However, unless you specify a preprocessor define, this auto linking will try and link to a name like "boost_system_msvc_mt_1_58.lib". That's not exact as I can't recall the exact name, but you get the idea. You specifically told boost to name your libraries with the system layout (boost_thread, boost_system) etc instead of the default, which includes the boost version, "MT" if multithreaded, the compiler version, and lots of other stuff in the name. So that's why the auto linking feature goes looking for such a crazy weird name and fails. To fix this, add "BOOST_AUTO_LINK_NOMANGLE" in the Preprocessor section of your C++ settings in visual studio.
More on that here. Note that the answer here gives you a different preprocessor definition to solve this problem. I believe I ended up using BOOST_AUTO_LINK_NOMANGLE instead (which ended up working for me) because the ALL_DYN_LINK macro turned out to be designed as an "internal" define that boost controls and sets itself. Not sure as it's been some time since I had this issue, but the define I provide seems to solve the same root issue anyway.

Boost 1.48.0 on Fedora Core 16

I'm trying to install ONLY the Boost Libraries 1.48.0 that are 100% complete from FC17 on an FC16 system. I have scoured the net but can't figure out how to do it. I have attempted to upgrade to rawhide but there are too many broken dependencies. I was hoping to just be able to upgrade that one package, as hopefully I don't believe I have too many programs installed that depend on Boost libraries (just the ones I'm coding).
I need to use the new features in 1.48.0. If I can't install them via an RPM, can I compile them as a normal user, store them in ~/lib and link against them?
I'm on FC16 x86_64.
Yes you can. You just need to export several shell environment variables in your shell profile to tell the compiler where to find your new boost header files and shared object files.
# For C and C++ header files search path
export C_INCLUDE_PATH=$your_new_boost_include_dir:$C_INCLUDE_PATH
export CPLUS_INCLUDE_PATH=$your_new_boost_include_dir:$CPLUS_INCLUDE_PATH
# link path
export LIBRARY_PATH=$your_new_boost_lib_dir:$LIBRARY_PATH
Usually you'll also need to do the following so that the compiled executables can be linked to the right version of shared object files at run time:
# run-time
export LD_LIBRARY_PATH=$your_new_boost_lib_dir:$LD_LIBRARY_PATH

Why are 3rd party libraries not found on the OCaml search path?

My configuration is as follows:
OCaml is installed by Homebrew, according to its default recipe. It lives in /usr/local/Cellar/objective-caml/3.12.0/[bin,lib,share], the contents of which are symlinked out to /usr/local/[bin,lib,share].
A 3rd party library (LLVM) installed symlinks into /usr/local/lib/ocaml/*. Critically, /usr/local/lib/ocaml is itself not a symlink to the Homebrew Cellar, but a folder containing links to the individual files under the OCaml Cellar path, so these 3rd party library files are in the /usr/local/lib/ocaml/ path but not the original path of
The standard OCaml compilers/interpreter/build tools consistently fail to find these 3rd party libraries unless they are explicitly pointed there (e.g. with ocamlbuild -cflags -I,/usr/local/lib/ocaml).
ld.conf lists:
/usr/local/lib/ocaml/stublibs
/usr/local/lib/ocaml
/usr/local/lib/ocaml/site-lib/pcre
which would seem to suggest that the compiler search path be set correctly, but I am not familiar with the inner workings of the toolchain.
Is this a known problem?
Is there a way to print the OCaml search paths actually used by the standard tools?
Assuming this is a consequence of the Homebrew configure and installation process (i.e. assuming that the problem is OCaml, as configured, assuming its actual lib path is /usr/local/Cellar/objective-caml/3.12.0/lib/ocaml rather than /usr/local/lib/ocaml), is it possible to force explicitly add additional search paths outside the --prefix during configuration?
Is it possible to extend the search paths for the entire environment after installation (by editing config files, rather than having to resort to potential reinstallation)?
Indeed as ygrek pointed out, the answer is ocamlfind. OCamlfind maintains a list of findlib-enabled¹ OCaml packages installed on your system, and it's easy to link them. Use
ocamlfind list
To get the list of packages, which can be piped to grep etc.
ocamlfind query mypackage
To get the installation path for the package (for more see ocamlfind query --help)
ocamlfind ocamlc -package mypackage .....
To compile something using the package as a dependency (-linkpkg is used in the final linking step to build the executable, you don't need it with -c -o foo.cmo for example).
ocamlfind can also be used through ocamlbuild. Prior to ocaml 3.12 you add to hack a bit the myocamlbuild.ml file (link), but since 3.12 it's dead easy: use package(foo) in the ocamlbuild tags if you want to use ocamlfind's package foo, and add option -use-ocamlfind to ocamlbuild's invocation.
¹: ocamlfind is the lingua franca of OCaml packages. If some of your third libraries don't register themselves through ocamlfind, you should hunt them, write a META file (it's easy), and send it to the library maintainer.
The only builtin search path for ocaml modules is the path to stdlib - see it with ocamlc -where. Paths referenced in ld.conf are used to find stublibs - C code compiled to dynamically loadable modules for bytecode ocaml programs using C bindings (without custom runtime). There is no way to "extend" search paths globally wrt ocaml installation.
The correct way is to add needed include paths when invoking ocaml tools. ocamlfind tool greatly helps to do this in system-independent way. E.g.:
ocamlfind ocamlc -linkpkg -package llvm ll.ml -o ll
High-level build systems like oasis/ocamlbuild/omake/etc hide all this stuff altogether and user only needs to provide names of dependent packages.
I think you're looking for $CAML_LD_LIBRARY_PATH to specify locations of additional libraries to link to, cfr. http://www.cs.jhu.edu/~scott/pl/caml/htmlman/manual024.html
You should be able to set the OCAMLLIB environment variable to get the result you're looking for. This is documented to help ocamlrun find the ld.conf file you noted in your question, but might also help you with ocamlc. The core distribution of OCaml doesn't have a configuration file for library paths, only the config file for locating C libraries.

Statically linking to a dynamic library. glibc

So. I have a problem where I have two versions of GCC on a machine.
3.4.6 and 4.1
This is due to some dependency issues with a new piece of software. (requires glibc 4.1)
When I go to link this new software with the 4.1 libraries it links fine. However, when it comes to executing the software it can't find the library, because it is looking at 3.4.6 in my LD_LIBRARY_PATH. If I set LD_LIBRARY_PATH to the 4.1 lib it blows up the shell,among killing other things, because the 3.4.6 libraries are used for that.
Its a bit of a catch 22.
Is there any way that at link time I can give an absolute path to that shared library without using the LD_LIBRARY_PATH?
This way I can hopefully have both versions, but only use 4.1 for this specific application?
You mean an absolute path that's used when the program is started and that's favored when looking for libraries? rpath is exactly that. It will overwrite the default search path and stuff set in LD_LIBRARY_PATH. Just tell gcc to pass it through to the linker:
g++ -Wl,-rpath,/usr/lib/my_4.1 -omy_binary *.cpp
You can make it show you the search processing (use help to make it give you more options):
[js#HOST2 cpp]$ LD_DEBUG=libs ./a.out
5859: find library=libc.so.6 [0]; searching
5859: search path=/usr/lib/my_4.1/tls/i686/sse2:/usr/lib/my_4.1/tls/i686:
/usr/lib/my_4.1/tls/sse2:/usr/lib/my_4.1/tls:
/usr/lib/my_4.1/i686/sse2:/usr/lib/my_4.1/i686:
/usr/lib/my_4.1/sse2:/usr/lib/my_4.1 (RPATH from file ./a.out)
5859: trying file=/usr/lib/my_4.1/tls/i686/sse2/libc.so.6
5859: ....
5859: search cache=/etc/ld.so.cache
5859: trying file=/lib/libc.so.6 (note: found here!)
5859:
not really an answer to your question, but an alternate solution:
you should be able to fix up your issues by adding your new lib path to /etc/ld.so.conf and running ldconfig as root.
Can't you set LD_LIBRARY_PATH just for the application that needs it?
I.e. instead of setting it globally as an exported variable, run your program as
LD_LIBRARY_PATH=/path/to/4.1/libs my_executabel
?
-k

Resources