In Meson, you get an opaque dependency object when you search for a library. How do you get the full path of the library that was found? In other words, what goes in "????" below?
compiler = meson.get_compiler('cpp')
extraLibDep = compiler.find_library('some library')
if extraLibDep.found()
extraLibPath = ????
endif
(The rataionale for wanting this info is that, if, after compilation, you want to package up your application, then you might need to ship some of the libraries with it. At least, this is the case on Windows and Mac.)
There is a way to get similar info when you're searching for a package, provided that Meson is using CMake to find the package, eg:
xercesDependency = dependency('XercesC',
required : true)
xercesLibPaths = xercesDependency.get_variable(cmake : 'PACKAGE_LIBRARIES')
But I can't find an equivalent for searching for, eg a library such as freetype or sqlite3.
(I have see How to get the include directories from a dependency in meson build system to which the only answer is "meson will handle all other things inside" but this isn't helpful when you want to export the information from meson.)
Related
I am trying to use libclang for some source parsing on linux. I have libclang-dev installed and it appears under the list of packages for apt on my system.
However when i try to add it as a dependency through any of:
dependency('clang')
dependency('libclang')
dependency('libclang-dev')
dependency('libclang-cpp-dev')
In all cases I get
Run-time dependency clang found: NO (tried pkgconfig and cmake)
Despite it no being able to find it in my system I thought I could just compile it from source. To that effect I tried this:
opt_var = cmake.subproject_options()
opt_var.append_link_args('-fPIC')
sub_proj = cmake.subproject('clang', options : opt_var)
clang = sub_proj.dependency('clang')
Which gives :
../subprojects/clang/meson.build:0:0: ERROR: Can't link non-PIC static library 'clangBasic' into shared library 'clang_cpp'. Use the 'pic' option to static_library to build with PIC.
I tested compilation of clang outside of meson (i.e. i made a build directory and did cmake .. && make) and it works so this is a problem with how meson is calling cmake, not with the library.
Any ideas?
I found a temporary solution but I hate it because it's too system specific, you can add the following:
cpp = meson.get_compiler('cpp')
includes = include_directories(['/usr/lib/llvm-13/include/'])
libclang_lib = cpp.find_library('clang', dirs:'/usr/lib/llvm-13/lib', header_include_directories: includes)
libclang = declare_dependency(dependencies:libclang_lib, include_directories:includes)
To your meson script. Then use libclang as a dependency.
I am still interested in an answer that is more general/less OS specific.
I was trying to use yaml-cpp in my project. It took me half an hour to correctly link the library by experimenting with the following names. After I finally stumbled across them in this file, I settled for this:
find_package(yaml-cpp REQUIRED)
include_directories(${YAML_INCLUDE_DIRS})
target_link_libraries(${YAML_CPP_LIBRARIES})
It works, but the way I was searching for those seems brainless.
How is it remotely possible to figure out the correct name of the include variables? It could be YAML_LIBS, YAML_LIBRARY, YAML_CPP_LIBRARIES, there is no standard, right? What is the appropriate way to determine the correct cmake config for most c++ libraries?
Thank you.
Most of FindXXX.cmake scripts have usage description at the top of them (as CMake comments started #). The same is true about XXXConfig.cmake (or xxx-config.cmake) scripts.
Command find_package(XXX) uses one of such scripts (the one which actually exists). So, before using this approach for discover the package, make sure that you have read the description "embedded" into such script.
In your case, yaml-cpp-config.cmake file (created in the build or in the install directory) contains following description:
# - Config file for the yaml-cpp package
# It defines the following variables
# YAML_CPP_INCLUDE_DIR - include directory
# YAML_CPP_LIBRARIES - libraries to link against
so proper usage of results of find_package(yaml-cpp) is
include_directories(${YAML_CPP_INCLUDE_DIRS})
target_link_libraries(<your-target> ${YAML_CPP_LIBRARIES})
I've got a project currently using CMake, which I would like to switch over to Bazel. The primary dependency is LLVM, which I use to generate LLVM IR. Looking around, there doesn't seem to be a whole lot of guidance on this as only TensorFlow seems to use LLVM from Bazel (and auto-generates its config as far as I can tell). There was also a thread on bazel-discuss I found which discussed a similar issue, though my attempts to replicate it have failed.
Currently, my best run has got to be this (fetcher.bzl):
def _impl(ctx):
# Download LLVM master
ctx.download_and_extract(url = "https://github.com/llvm-mirror/llvm/archive/master.zip")
# Run `cmake llvm-master` to generate configuration.
ctx.execute(["cmake", "llvm-master"])
# The bazel-discuss thread says to delete llvm-master, but I've
# found that only generated files are pulled out of master, so all
# the non-generated ones get dropped if I delete this.
# ctx.execute(["rm", "-r", "llvm-master"])
# Generate a BUILD file for the LLVM dependency.
ctx.file('BUILD', """
# Build a library with all the LLVM code in it.
cc_library(
name = "lib",
srcs = glob(["**/*.cpp"]),
hdrs = glob(["**/*.h"]),
# Include the x86 target and all include files.
# Add those under llvm-master/... as well because only built files
# seem to appear under include/...
copts = [
"-Ilib/Target/X86",
"-Iinclude",
"-Illvm-master/lib/Target/X86",
"-Illvm-master/include",
],
# Include here as well, not sure whether this or copts is
# actually doing the work.
includes = [
"include",
"llvm-master/include",
],
visibility = ["//visibility:public"],
# Currently picking up some gtest targets, I have that dependency
# already, so just link it here until I filter those out.
deps = [
"#gtest//:gtest_main",
],
)
""")
# Generate an empty workspace file
ctx.file('WORKSPACE', '')
get_llvm = repository_rule(implementation = _impl)
And then my WORKSPACE file looks like the following:
load(":fetcher.bzl", "get_llvm")
git_repository(
name = "gflags",
commit = "46f73f88b18aee341538c0dfc22b1710a6abedef", # 2.2.1
remote = "https://github.com/gflags/gflags.git",
)
new_http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.8.0.zip",
sha256 = "f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf",
build_file = "gtest.BUILD",
strip_prefix = "googletest-release-1.8.0",
)
get_llvm(name = "llvm")
I would then run this with bazel build #llvm//:lib --verbose_failures.
I would consistently get errors from missing header files. Eventually I found that running cmake llvm-master generated many header files into the current directory, but seemed to leave the non-generated ones in llvm-master/. I added the same include directories under llvm-master/ and that seems to catch a lot of the files. However, currently it seems that tblgen is not running and I am still missing critical headers required for the compilation. My current error is:
In file included from external/llvm/llvm-master/include/llvm/CodeGen/MachineOperand.h:18:0,
from external/llvm/llvm-master/include/llvm/CodeGen/MachineInstr.h:24,
from external/llvm/llvm-master/include/llvm/CodeGen/MachineBasicBlock.h:22,
from external/llvm/llvm-master/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h:20,
from external/llvm/llvm-master/include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h:13,
from external/llvm/llvm-master/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp:10:
external/llvm/llvm-master/include/llvm/IR/Intrinsics.h:42:38: fatal error: llvm/IR/IntrinsicEnums.inc: No such file or directory
Attempting to find this file in particular, I don't see any IntrinsicEnums.inc, IntrinsicEnums.h, or IntrinsicEnums.dt. I do see a lot of Instrinsics*.td, so maybe one of them generates this particular file?
It seems like tblgen is supposed to convert the *.td files to *.h and *.cpp files (please correct me if I am misunderstanding). However, this doesn't seem to be running. I saw that in Tensorflow's project, they have a gentbl() BUILD macro, though it is not practical for me to copy it as it has way too many dependencies on the rest of Tensorflow's build infrastructure.
Is there any way to do this without something as big and complex as Tensorflow's system?
I posted to the llvm-dev mailing list here and got some interesting responses. LLVM definitely wasn't designed to support Bazel and doesn't do so particularly well. It appears to be theoretically possible by using Ninja to output all the compile commands and then consume them from Bazel. This is likely to be pretty difficult and would require a separate tool which outputs Skylark code to be run by Bazel.
This seemed pretty complex for the scale of project I was working on, so my workaround was to download the pre-built binaries from releases.llvm.org. This included all the necessary headers, libraries, and tooling binaries. I was able to make a simple but powerful toolchain based around this in Bazel for my custom programming language.
Simple example (limited but focused): https://github.com/dgp1130/llvm-bazel-foolang
Full example (more complex and less focused): https://github.com/dgp1130/sanity-lang
I am trying to write a simple application with GLFW on Linux. Right now the main file (the only file) is basically just a few lines of code to make sure the dynamic library linked correctly. Here it is:
#include <GLFW/glfw3.h>
#include <iostream>
int main()
{
glfwInit();
std::cout << "It works this far!" << std::endl;
glfwTerminate();
}
The include files are stored in a directory labelled "include" and the library files are stored in a directory labelled "lib". As of right now, I am compiling the program with the following line:
g++ -Wl,-Rlib -Iinclude -Llib test.cpp -o test -lglfw.3.2
It compiles and links just fine, but when I try to execute it, I get the following error:
./test: error while loading shared libraries: libglfw.so.3: cannot open shared object file: No such file or directory
Now, before you rush to downvote this question into oblivion and mark it as a duplicate, at least allow me to explain why I believe my question is different enough to not be a duplicate. I already attempted the solutions that the other questions presented, but it was unsuccessful. As you can see, I tried setting the path to the library during linking with the -Wl,-Rlib tag. I also tried setting LD_LIBRARY_PATH to point to the location of my libraries (the 'lib' folder), but it still threw the same error. (It didn't matter if the path was relative or absolute.)
So, the next thing I tried was running the ldd command on the executable. I got some other dependencies that were working just fine, but importantly, I got this:
libglfw.so.3 => not found
For some reason, it insists on looking for libglfw.so.3. It will not have it any other way. Upon renaming the library from libglfw.3.2.so to libglfw.so.3, the program executed just fine and printed It works this far! as if there were no problems at all.
Why would this happen?
For some reason, it insists on looking for libglfw.so.3. ... Upon renaming the library from libglfw.3.2.so to libglfw.so.3 ...
The ELF executables contain the exact name of the dynamic libraries used.
If the executable contains the library name "libglfw.so.3" the file must be named exactly like this.
The file naming scheme is intentionally done in a way that not the "full" version is coded into the file name: This way a later version ("libglfw.so.3.15") will work with the executable.
Normally there should be a symbolic link to the latest version of the library installed:
libglfw.so.3 -> libglfw.so.3.2
This symbolic link seems to be missing on your computer. I would say that this is an installation problem!
EDIT
The question could be: Why is the file name stored in the executable file not libglfw.3.2.so but libglfw.so.3?
The answer has to do with the backward compatibility when a new version of a library is installed:
Normally you would use the switch -lglfw and a symbolic link named libglfw.so is looked up.
If you stored the file name libglfw.so in the executable file and a new, incompatible version if this library (libglfw.so.4) is installed you would have no chance to get the program running by having both versions of the library installed.
To enable backward compatibility by having both versions of the library installed the "real" symbolic link name of the library (libglfw.so.3) must be stored in the executable file.
Therefore the "expected" file name of a library is stored in the library itself: Inside the file libglfw.so.3.2 you'll find some information that the file expects itself to be stored as libglfw.so.3.
The linker will use this information about the file name because it assumes that the library name given in the linker switch (-lglfw) is less "precise" than the name stored in the library itself.
For some reason, it insists on looking for libglfw.so.3. It will not have it any other way.
This is the Linux convention for shared libraries which is described here among other places. For Linux libfoo.so.x.y.z is considered to have the same ABI as libfoo.so.x. Usually when shared libraries are installed (e.g. via rpm, dpkg, etc.) there's an invocation of ldconfig that happens so that the just installed libraries have a symlink following the convention installed that references the library. Also these libs (if installed to a "trusted location"), are added to a linker cache for performance reasons.
It compiles and links just fine, but when I try to execute it, I get the following error:
./test: error while loading shared libraries: libglfw.so.3: cannot open shared object file: No such file or directory
libglfw.so.3 isn't on ld-linux.so's path.
As you can see, I tried setting the path to the library during linking with the -Wl,-Rlib
Still won't find it -- libglfw.so.3 isn't on ld-linux.so's path. You can add it by doing something like:
ldconfig -n /path/to/lib
Which should output the requisite libglfw.so.3 symlink for your lib.
IIRC setting the rpath might require a full path.
I also tried setting LD_LIBRARY_PATH to point to the location of my libraries
Again, libglfw.so.3 isn't on ld-linux.so's path.
One of my executables requires libgfortran.so. Typically I'd just add the -lgfortran switch to the compile line and it links automatically with g++. However, I'm trying to find the library with CMAKE using:
find_library(GFORTRAN_LIBRARY NAMES gfortran)
target_link_libraries(ncorr_test ${GFORTRAN_LIBRARY})
However, this fails to the find the library. It turns out the only way that has worked so far is if I include the entire library name like so:
find_library(GFORTRAN_LIBRARY NAMES libgfortran.so.3)
target_link_libraries(ncorr_test ${GFORTRAN_LIBRARY})
Then, it will link properly:
/usr/bin/c++ ... /usr/lib/x86_64-linux-gnu/libgfortran.so.3 ...
However, including the whole .so.3 is not very portable. Does anyone know of a better way to do this? Typically libraries I need to use are just installed in /usr/local/lib and searching for the library name without the "lib" and extension works (i.e. find_library(FFTW_LIBRARY NAMES fftw3) will find libfftw3.a in /usr/local/lib just fine).
EDIT:
find_library(GFORTRAN_LIBRARY NAMES libgfortran.so) does not work either. Only libgfortran.so.3 has worked so far.
Using locate libgfortran outputs:
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgfortran.a
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgfortran.so
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgfortran.spec
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgfortranbegin.a
/usr/lib/x86_64-linux-gnu/libgfortran.so.3
/usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
/usr/local/MATLAB/R2014a/sys/os/glnxa64/libgfortran.so.3
/usr/local/MATLAB/R2014a/sys/os/glnxa64/libgfortran.so.3.0.0
/usr/share/doc/libgfortran-4.8-dev
/usr/share/doc/libgfortran3
/var/lib/dpkg/info/libgfortran-4.8-dev:amd64.list
/var/lib/dpkg/info/libgfortran-4.8-dev:amd64.md5sums
/var/lib/dpkg/info/libgfortran3:amd64.list
/var/lib/dpkg/info/libgfortran3:amd64.md5sums
/var/lib/dpkg/info/libgfortran3:amd64.postinst
/var/lib/dpkg/info/libgfortran3:amd64.postrm
/var/lib/dpkg/info/libgfortran3:amd64.shlibs
/var/lib/dpkg/info/libgfortran3:amd64.symbols
EDIT2:
For now I'll just require the user to copy libgfortran.a over to their usr\local\lib directory
Looks like you either miss dev package on your linux distribution, which should install .so link, or path where such link located is missing when cmake does lookup. Try to find libgfortran.so link, usually it is located the same place where .so.3 is, if you cannot find it install missing dev package, if you can check why that path is not included in cmake.