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

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.

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})
....

cross-gcc doesn't search for target as and ld in path?

I've successfully built a couple of cross-gcc compilers, hosted on OSX Lion and targeting both i386-pc-solaris2.10 and x86_64-linux-gnu.
I have 2.22 binutils for those target installed under $BINUTILSROOT and $BINUTILSROOT/bin in my PATH. Reading http://gcc.gnu.org/install/configure.html, in particular
--with-as=pathname
Specify that the compiler should use the assembler pointed to by pathname, rather than the one found by the standard rules to find an assembler, which are:
Unless GCC is being built with a cross compiler, check the libexec/gcc/target/version directory. libexec defaults to exec-prefix/libexec; exec-prefix defaults to prefix, which defaults to /usr/local unless overridden by the --prefix=pathname switch described above. target is the target system triple, such as `sparc-sun-solaris2.7', and version denotes the GCC version, such as 3.0.
If the target system is the same that you are building on, check operating system specific directories (e.g. /usr/ccs/bin on Sun Solaris 2).
Check in the PATH for a tool whose name is prefixed by the target system triple.
Check in the PATH for a tool whose name is not prefixed by the target system triple, if the host and target system triple are the same (in other words, we use a host tool if it can be used for the target as well).
I thought my -gcc (configured with --with-gnu-as --with-gnu-ld) would have picked up respectively i386-pc-solaris2.10-as and x86_64-linux-gnu-as (and corresponding -ld) because they are in $BINUTILSROOT/bin which is in the PATH and so the 3rd bullet from the above list should apply.
But this doesn't seem to work, and I've confirmed with dtrace that -gcc doesn't search for -as and -ld in the PATH.
The only solution I've found to be working is to also fully specify as and ld adding
--with-as=$BINUTILSROOT/bin/-as --with-ld=$BINUTILSROOT/bin/-ld
when configuring gcc.
Am I misinterpreting gcc docs, or this is the only way to have cross-compilation working?
Ordinarily you'd install a cross-compiler in the same directory as your cross-binutils. If you do that it'll Just Work.
If you're not installing the compiler into the same directory because you want to "stage" it for building a package, then you should configure with the --prefix of the final installed location (in which the binutils should already be present), and then install with
make DESTDIR=/path/to/staging/dir install
to override the prefix setting. You'd then copy those files into the true prefix (presumably as part of a package install) before you use them.
If you don't want to install in the same directory for another reason then you have to specify the path as you've discovered. There are other ways to make it work, but --with-as is the intended solution. If you really don't like that solution, then you can do
make configure-gcc
ln -s $BINUTILSROOT/bin/as gcc/as
ln -s $BINUTILSROOT/bin/ld gcc/ld
That will make the build work (IIRC), but the final installed compiler will still look in the standard places. In fact, this works because, during build only, the gcc directory is one of the standard places.
The reason for all this is that it doesn't use "x86_64-linux-gnu-as": it actually uses "prefix/x86_64-linux-gnu/bin/as" and if that doesn't exist it looks in the other standard places for "as", and typically finds the host "/usr/bin/as" which doesn't work well (and leads to very confusing error messages).

USB GCC Development Environment with Libraries

I'm trying to get something of an environment on a usb stick to develop C++ code in. I plan to use other computers, most of the time linux, to work on this from a command line using g++ and make.
The problem is I need to use some libraries, like Lua and OpenGL, which the computers don't have. I cannot add them to the normal directories, I do not have root on these computers. Most of the solutions I've found involve putting things in /usr/lib/ and the like, but I cannot do that. I've also attempted adding options like '-L/media//lib', which is where they are kept, and it didn't work. When compiling, I get the same errors I got when first switching to an OS with the libraries not installed.
Is there somewhere on the computer outside of /usr/ I can put them, or a way to make gcc 'see' them?
You need more than the libraries to be able to compile code utilizing those libraries. (I'm assuming Linux here, things might be slightly different on e.g. OSX,BSDs,Cygwin,Mingw..)
Libraries
For development you need these 3 things when your code uses a library:
The library header files, .h files
The library development files, libXXX.so or libXXX.a typically
The library runtime files , libXXX.so.Y where Y is a version number. These are not needed if you statically link in the library.
You seem to be missing the header files (?) Add them to your usb stick, say under /media/include
Development
Use (e.g.) the compiler flag -I/media/include when compiling source code to refer to a non-standard location of header files.
Use the compiler/linker flag -L/media/lib to refer to non-standard location of libraries.
You might be missing the first step.
Running
For dynamically linked libraries, the system will load those only from default locations, typically /lib/ , /usr/lib/
Learn the ldd tool to help debug this step.
You need to tell the system where to load additional libraries when you're running a program, here's 3 alternatives:
Systemwide: Edit /etc/ld.so.conf and add /media/libs there. Run ldconfig -a afterwards.
Local, to the current shell only. set the LD_LIBRARY_PATH environment variable to refer to /media/lib, run export LD_LIBRARY_PATH=/media/lib
Executable: Hardcode the non-standard library path in the executable. You add this to the linking step when creating your executable: -Wl,-rpath,/media/lib
Etc.
There could be other reasons things are not working out, if so,
show us the output of ls -l /media/libs , and where you put the library header files, the command line you use to compile/link, and the exact errors you get.
Missing the headers and/or development libraries (for dynamic libraries there is usually a symlink from a libXXX.so to a libXXX.so.Y , the linker needs the libXXX.so , it will not look directly at libXXX.so.Y)
using libraries not compatible with your current OS/architecture. (libraries compiled on one linux distro is often not compatible with another distro, or even another minor version of the same distro)
using an usb stick with a FAT32 filesystem, you'll get in trouble with symlinks..

Scip integrate with mingw and msys

How can I integrate SCIP with MinGW and Msys?
Whilst you are waiting for a real answer, I can already guide you to this page from the official site on how to build SCIP (see below). For actual integration there is a pointer in the faq:
How do I construct a problem instance in SCIP?
First you have to create a SCIP object via SCIPcreate(), then you
start to build the problem via SCIPcreateProb(). Then you create
variables via SCIPcreateVar() and add them to the problem via
SCIPaddVar(). The same has to be done for the constraints. For
example, if you want to fill in the rows of a general MIP, you have to
call SCIPcreateConsLinear(), SCIPaddConsLinear() and additionally
SCIPreleaseCons() after finishing. If all variables and constraints
are present, you can initiate the solution process via SCIPsolve().
Make sure to also call SCIPreleaseVar() if you do not need the
variable pointer anymore. For an explanation of creating and releasing
objects, please see the doxygen documentation.
NOTE: See the directories "examples/MIPsolver/" and "examples/Queens/" for simple examples
Remarks on Building/Installing under Windows using MinGW (from http://scip.zib.de/doc/html/INSTALL.php)
To build your own Windows binaries under Windows, we recommend using
the MinGW-Compiler with MSYS from mingw.org
First install MSYS, then MinGW to the mingw folder inside the msys
folder. Now you need to install the following packages to the mingw
folder:
- zlib (or use ZLIB=false ZIMPL=false since zlib is needed for ZIMPL and ZIMPL-support in SCIP)
- pcre (or use ZIMPL=false since pcre is needed for ZIMPL and ZIMPL-support in SCIP)
- gmplib (or use ZIMPL=false since gmplib is needed for ZIMPL and ZIMPL-support in SCIP)
(After calling "make clean" in the ZIMPL folder you will also need
flex and bison to remake ZIMPL. We recommend NOT to use "make clean"
inside the ZIMPL-folder if you do not have these packages installed.)
You can download these additional packages as precompiled binaries for
example from: http://gnuwin32.sourceforge.net/packages.html
(zlib&pcre) http://cs.nyu.edu/exact/core/gmp/ (gmplib) or compile the
source on your own from the project homepages: http://www.zlib.net/
http://www.pcre.org/ http://www.gmplib.org/ (The command "./configure
--prefix=/mingw ; make ; make install" should succeed without problems and installs the packages into the mingw folder.)
Now "make READLINE=false" should be compiling without errors. Please
note that we do NOT support creating the doxygen documentation or
readline-usage under Windows.
Since there are no real symlinks in MSYS, the include and library
files of SoPlex and ZIMPL are actually copied into the
SCIP-lib-folder. When you recompile ZIMPL or SoPlex after compiling
SCIP you have to copy the libraries manually into the SCIP-lib-folder
and recompile SCIP afterwards.

How to force Boost to use rpath?

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).

Resources