When defining external dependencies in meson, can you add search paths? - build

When defining a target in meson, you can declare dependencies on external projects using the following syntax:
zdep = dependency('zlib', version : '>=1.2.8')
exe = executable('zlibprog', 'prog.c', dependencies : zdep)
This checks the standard include locations, which works well on Linux, but not so well on other platforms.
Is there a way to add additional include and library paths for meson to check when declaring dependencies?

As the documentation says: dependency() "Finds an external dependency [...] with pkg-config if possible and with library-specific fallback detection logic otherwise."
So, if you mean to set PKG_CONFIG_PATH, you can do that as usual:
$ export PKG_CONFIG_PATH=/wherever/your/installed/dir/is/
$ meson ....
Or, you can use back-end specific variables, ie. BOOST_ROOT. Check the doc for more info.
If you ment to find other libraries not using pkg-config, you can add a dirs keyword argument to point to the directory your libraries are in.

Related

How can I control what symbols are exported from a shared library in Bazel?

I'm learning Bazel, because I have to use it at work. I have a simple build rule that creates a library from a single file and I would like control what is exported by the linker by using a linker version file. (I'm on Linux)
So I tried:
cc_library (
name ="thelib",
srcs = ["lib.cpp"],
linkopts = ["-Wl,--version-script,lib.ver"]
)
And it tells me "No such file or directory".
What have I tried:
I tried a path relative to the directory I issue the bazel build command with no avail.
cc_library()'s documentation says "linkopts" support make variable substitution so I listed the make variables with bazel info --show_make_env it showed me a variable called workspace
so I then tried $(workspace)/lib/lib.ver but then it says $(workspace) not defined so Bazel is a liar.
The only thing that works is spelling the absolute path to the linker script but I don't want to push that.
cc_library() has a win_def_file option but guess what, that's Windows only.
A self-closed github issue suggests that I should pass the filename as a separate argument, it doesn't work either.
Using -fvisiblity=hidden and export using __attribute__ to export is not an option because the standard C++ library overrides it and forces exporting of the symbols you don't want to appear on the interface (the library is used using extern "C" interface only I don't want any other garbage appear on it).
There doesn't seem to be an option in Bazel to specify the symbols to export natively.
At this point I completely ran out of ideas. Any help is appreciated.
First of all, shared libraries are generally declared with cc_binary in conjunction with its linkshared attribute rather than cc_library. This is counterintuitive but reflects the intention that cc_binary creates a transitive link while cc_library declares an intermediate library. (More adventurous folks may try out cc_shared_library
Second of all, it's possible to use version scripts (and other linker scripts) by using them in linkopts and declaring them as a dependency in deps.
So, all together:
cc_binary(
name = 'mylib.so',
linkshared = True,
srcs = ['mylib.cc'],
linkopts = ['-Wl,-version-script=$(location version-script.lds)'],
deps = [
'version-script.lds',
]
)

How to link external C++ library to my project on Mac OSX [duplicate]

I have 2 folders "inc" and "lib" in my project which have headers and static libs respectively. How do I tell cmake to use those 2 directories for include and linking respectively?
The simplest way of doing this would be to add
include_directories(${CMAKE_SOURCE_DIR}/inc)
link_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(foo ${FOO_SRCS})
target_link_libraries(foo bar) # libbar.so is found in ${CMAKE_SOURCE_DIR}/lib
The modern CMake version that doesn't add the -I and -L flags to every compiler invocation would be to use imported libraries:
add_library(bar SHARED IMPORTED) # or STATIC instead of SHARED
set_target_properties(bar PROPERTIES
IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/lib/libbar.so"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libbar"
)
set(FOO_SRCS "foo.cpp")
add_executable(foo ${FOO_SRCS})
target_link_libraries(foo bar) # also adds the required include path
If setting the INTERFACE_INCLUDE_DIRECTORIES doesn't add the path, older versions of CMake also allow you to use target_include_directories(bar PUBLIC /path/to/include). However, this no longer works with CMake 3.6 or newer.
You had better use find_library command instead of link_directories. Concretely speaking there are two ways:
designate the path within the command
find_library(NAMES gtest PATHS path1 path2 ... pathN)
set the variable CMAKE_LIBRARY_PATH
set(CMAKE_LIBRARY_PATH path1 path2)
find_library(NAMES gtest)
the reason is as flowings:
Note This command is rarely necessary and should be avoided where there are other choices. Prefer to pass full absolute paths to
libraries where possible, since this ensures the correct library will
always be linked. The find_library() command provides the full path,
which can generally be used directly in calls to
target_link_libraries(). Situations where a library search path may be
needed include: Project generators like Xcode where the user can
switch target architecture at build time, but a full path to a library
cannot be used because it only provides one architecture (i.e. it is
not a universal binary).
Libraries may themselves have other private library dependencies that
expect to be found via RPATH mechanisms, but some linkers are not able
to fully decode those paths (e.g. due to the presence of things like
$ORIGIN).
If a library search path must be provided, prefer to localize the
effect where possible by using the target_link_directories() command
rather than link_directories(). The target-specific command can also
control how the search directories propagate to other dependent
targets.
might fail working with link_directories, then add each static library like following:
target_link_libraries(foo /path_to_static_library/libbar.a)

How to build a shared library (.so) without hardcoded full dependency paths?

I need to build two 3rd party shared libraries, so their .so files will be reused by other projects. However, after build one of these libraries contains hardcoded path to another. This path is invalid on other machines and causes linker warnings. How can I prevent the full path from being embedded in the resulting .so files?
Details:
First library source: ~/dev/A
Second library source: ~/dev/B
Both of them have configure script to generate make files. Library B depends on A. So, first I build A:
$ ~/dev/A/configure --prefix=~/dev/A-install
$ make && make install
Then I build B:
$ ~/dev/B/configure --prefix=~/dev/B-install --with-A=~/dev/A-install
$ make && make install
Then I want to upload the contents of ~/dev/A-install and ~/dev/B-install to our file server, so other teams and build machines can use the binaries. But they get linker warnings when they try to use B:
/usr/bin/ld: warning: libA.so.2, needed by /.../deps/B/lib/libB.so, not found (try using -rpath or -rpath-link)
When I run ldd libB.so it gives:
...
libA.so.2 => /home/alex/dev/A-install/lib/libA.so.2
Obviously this path exists only on my machine and cannot be found on other machines.
How can I remove full hardcoded path from libB.so?
Thanks.
You have to use --prefix value that will be valid in the runtime environment for both packages!
Than you override prefix or DESTDIR (prefix replaces the prefix, DESTDIR is prepended to it, but works more reliably) on the make command-line when installing. Like:
~/dev/A$ ./configure
~/dev/A$ make
~/dev/A$ make install prefix=~/dev/A-install
~/dev/B$ ./configure --with-A=~/dev/A-install
~/dev/B$ make
~/dev/B$ make install prefix=~/dev/B-install
or (which is preferred and is how all package-building tools use it):
~/dev/A$ ./configure
~/dev/A$ make
~/dev/A$ make install DESTDIR=~/dev/A-install
~/dev/B$ ./configure --with-A=~/dev/A-install/usr/local
~/dev/B$ make
~/dev/B$ make install prefix=~/dev/B-install
because this way you are installing to ~/dev/A-install/$prefix, so with default prefix ~/dev/A-install/usr/local. The advantage of this later option is, that if you redefine some specific installation paths without refering to prefix (say --sysconfdir=/etc), DESTDIR will still get prepended to it, while it won't be affected by prefix.
-Wl,-rpath,~/deps/A/lib:~/deps/B/lib:~/dev/MyApp/bin
This linker option is responsible for saving the path inside the library. You need somehow to remove this.
See with ./configure --help if there's some option that could influence this. Another option is to edit manually the makefile and remove this option.
== edit2 ==
One more thing
-L~/deps/A/lib -L~/deps/B/lib ~/deps/A/lib/libA.so ~/deps/B/lib/libB.so
If libA.so and libB.so don't have SONAME, linking them like "~/deps/A/lib/libA.so" will also cause saving the path. Soname is set using -Wl,-soname,<soname> linker option when building shared library.
If soname is set in the shared library, linking it using "~/deps/A/lib/libA.so" form is ok.
Like Jan mentioned in the comments, the better way is using "-Llibrary/path -llibrary_name" without rpath.
-L~/deps/A/lib -L~/deps/B/lib -lA -lB
When I run ldd libB.so it gives:
libA.so.2 => /home/alex/dev/A-install/lib/libA.so.2
The low-level solution to this problem is to use the option "-soname=libA.so" when you link the libA.so library. By having SONAME defined for a shared object, the linker will not embed absolute paths when linking against that shared object.
The OP is using "configure", so this isn't an easy solution to implement unless he is willing to go into the bowels of the Makefile generated by the configure script.
Shared libraries and executables have a list of directories to look for shared libraries, in addition to the list in the operating system's configuration. RPATH is used to add shared library search paths, used at runtime.
If you want a relative path to be used in RPATH, there is a special syntax that most Linux/UNIX (but not AIX) systems support - $ORIGIN or ${ORIGIN}.
$ORIGIN will expand at runtime to the directory where the binary resides - either the library or executable.
So if you put executable binaries in prefix/bin/ and shared libraries in prefix/lib/ you can add an entry to RPATH like ${ORIGIN}/../lib and this will expand at runtime to prefix/bin/../lib/
It's often a little trick to get the syntax correct in a Makefile, because you have to escape the $ in ORIGIN so it will not be expanded. It's typical to do this in a Makefile:
g++ -Wl,-rpath=\$${ORIGIN}/../lib
Both Make and the shell will want to look in your environment for a variable called ORIGIN - so it needs to be double-escaped.
I just got caught out thinking I had the same problem.
None of the above answers helped me.
Whenever I tried
ldd libB.so
I would get in the output:
libA.so.1 => /home/me/localpath/lib/libA.so.1.0
and so I thought I had a hardcoded path. Turns out that I had forgotten I had LD_LIBRARY_PATH set for local testing. Clearing LD_LIBRARY_PATH meant that ldd found the correct installed library in /usr/lib/
Perhaps using the -rpath and -soname options to ld could help (assuming a binutils or binutils.gold package for ld on a recent Linux system)?

qmake : Build library without the symlinks and 'lib' prefix

I require a very simple mechanism in my application, where my project is built as a shared library '.so' or '.dll', but what I want is:
ExampleAppOne.so
I get:
libExampleAppOne.so -> libExampleAppOne.so.1.0.0
libExampleAppOne.so.1 -> libExampleAppOne.so.1.0.0
libExampleAppOne.so.1.0 -> libExampleAppOne.so.1.0.0
I don't even want the 'lib' prefix. In the .pro file, all I can do is change the INSTALLS variable (that is because my third requirement IS that the library be built in a specific directory).
Also, I have a fourth, related requirement: When I ask QLibrary to load the library, I want it to specifically search for a library in a very specific path and a library that matches the EXACT name given to it. No 'lib' prefix matching, no 'version string' searching, no looking into LD_LIBRARY_PATH...
Any help is appreciated.
Regards,
rohan
add the following to you .pro file
# disables the lib prefix
CONFIG += no_plugin_name_prefix
# disable symlinks & versioning
CONFIG += plugin
Adding plugin to the CONFIG variable should disable versioning and the generation of symbolic links to the library.
I don't know of a simple way to disable the lib prefix though. You way want to dig into the provided QMake spec files to see how the default processing is implemented.

organizing external libraries and include files

Over the years my projects use more and more external libraries, and the way I did it starts feeling more and more awkward (although, that has to be said, it does work flawlessly). I use VS on Windows, CMake on others, and CodeComposer for targetting Digital Signal Processors (DSPs) on Windows. Except for the DSPs, both 32bit and 64bit platforms are used.
Here's a sample of what I am doing now; note that as shown, the different external libraries themselves are not always organized in the same way. Some have different lib/include/src folders, others have a single src folder. Some came ready-to-use with static and/or shared libraries, others were built
/path/to/projects
/projectA
/projectB
/path/to/apis
/apiA
/src
/include
/lib
/apiB
/include
/i386/lib
/amd64/lib
/path/to/otherapis
/apiC
/src
/path/to/sharedlibs
/apiA_x86.lib -->some libs were built in all possible configurations
/apiA_x86d.lib
/apiA_x64.lib
/apiA_x64d.lib
/apiA_static_x86.lib
/apiB.lib -->other libs have just one import library
/path/to/dlls -->most of this directory also gets distributed to clients
/apiA_x86.dll and it's in the PATH
/apiB.dll
Each time I add an external libary, I roughly use this process:
build it, if needed, for different configurations (release/debug/platform)
copy it's static and/or import libraries to 'sharedlibs'
copy it's shared libraries to 'dlls'
add an environment variable, eg 'API_A_DIR' that points to the root for ApiA, like '/path/to/apis/apiA'
create a VS property sheet and a CMake file to state include path and eventually the library name, like include = '$(API_A_DIR)/Include' and lib = apiA.lib
add the propertysheet/cmake file to the project needing the library
It's especially step 4 and 5 that are bothering me. I am pretty sure I am not the only one facing this problem, and would like see how others deal with this.
I was thinking to get rid of the environment variables per library, and use just one 'API_INCLUDE_DIR' and populating it with the include files in an organized way:
/path/to/api/include
/apiA
/apiB
/apiC
This way I do not need the include path in the propertysheets nor the environment variables. For libs that are only used on windows I even don't need a propertysheet at all as I can use #pragmas to instruct the linker what library to link to.
Also in the code it will be more clear what gets included, and no need for wrappers to include files having the same name but are from different libraries:
#include <apiA/header.h>
#include <apiB/header.h>
#include <apiC_version1/header.h>
The withdrawal is off course that I have to copy include files, and possibly** introduce duplicates on the filesystem, but that looks like a minor price to pay, doesn't it?
** actually once libraries are built, the only thing I need from them is the include files and thie libs. Since each of those would have a dedicated directory, the original source tree is not needed anymore so can be deleted..
Why not use file system links?
ln -s /path/to/apis/apiA/include /path/to/api/include/apiA
Voilá. Similar can be done on Windows, but I don't have the command line handy right now.