Is there any simple way to link at runtime a locally built library to a test with CMAKE?
For example:
enable_testing()
add_executable(Test test/Test.cpp)
target_link_libraries(Test -L../lib/libzmq/build/lib/ zmq)
add_test(
NAME TestClientZmq
COMMAND "LD_PRELOAD=../lib/libzmq/build/lib/libzmq.so Test")
Running the test will complain about the missing library at runtime:
error while loading shared libraries: libzmq.so.4.2.0: cannot open shared object file: No such file or directory
I can either:
Set LD_PRELOAD when running ctest
Write a wrapper script which does this and then calls the executable (what I have currently)
I would prefer to do everything in cmake though, since I think it's best to keep all this configuration in a single place to avoid bugs in the future.
Add
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
to your CMakeLists.txt. As explained in this wiki article.
After build, use the below command to make sure the RPATH is properly set:
objdump -x Test | grep RPATH
Related
I am modernizing our CMake build system and switching to static compilation of all dependencies so I can deploy the application as single binary. One of the dependencies is LibXml2 which is statically compiled (Environment MSVC 2019 x64 Native):
cscript configure.js iconv=no compiler=msvc cruntime=/MT debug=yes static=yes prefix=libxml
nmake Makefile.msvc libxml install
This generates the DLL win32\libxml\bin\libxml2.dll and the LIB files win32\libxml\lib\libxml2.liband win32\libxml\lib\libxml2_a.lib.
My CMake file looks like this:
find_package(LibXml2 REQUIRED)
add_executable(testapp WIN32)
target_sources(testapp
PRIVATE
Main.cpp
)
target_include_directories(testapp PUBLIC ${LIBXML_LIBRARIES})
target_link_libraries(testapp PRIVATE LibXml2::LibXml2)
Problem: It looks like the find module FindLibXml2 picks up the relocatable shared DLL, but not the static LIB archive. Thus the application is linked against the dynamic library.
Question: How can I use the find module script, but link against the static version of LibXml2? Is this even possible or do I have to write an own find script?
User #alex-reinking gave the important tip: Set the cached variable before calling the find module - and not afterwards.
Because I don't want to hardcode the path (and can't because I have a debug and release build of LibXml2), I use find_library to find the static library (Note: I added the libxml directory via CMAKE_PREFIX_PATH):
find_library(STATIC_LIBXML2_LIBRARY NAMES libxml2_a)
message(STATUS "Found library: ${STATIC_LIBXML2_LIBRARY}")
set(LIBXML2_LIBRARY ${STATIC_LIBXML2_LIBRARY})
find_package(LibXml2 REQUIRED)
I am trying to setup an environment to develop an Ogre3D application. I have manually compiled Ogre into folder /opt/Ogre3D/ogre-1.11.5/build and created a CMake project in CLion with this content:
cmake_minimum_required(VERSION 3.13)
project(sample)
set(CMAKE_CXX_STANDARD 14)
set(OGRE_DIR /opt/Ogre3D/ogre-1.11.5/build/sdk/cmake)
# specify which version and components you need
find_package(OGRE 1.11 REQUIRED COMPONENTS Bites RTShaderSystem)
# copy resource.cfg next to our binaries where OGRE looks for it
file(COPY ${OGRE_CONFIG_DIR}/resources.cfg DESTINATION ${CMAKE_BINARY_DIR})
add_executable(sample main.cpp)
target_link_libraries(sample ${OGRE_LIBRARIES})
when I try to run it, compilation is OK but then it can't execute it:
/Users/diego/CLionProjects/ogre/sample/cmake-build-debug/sample
dyld: Library not loaded: #executable_path/../Frameworks/OgreBites.framework/Versions/1.11.5/OgreBites
Referenced from: /Users/diego/CLionProjects/ogre/sample/cmake-build-debug/sample
Reason: image not found
Process finished with exit code 6
I have looked at otool -l /opt/Ogre3D/ogre-1.11.5/build/lib/macosx/OgreBites.framework/Versions/1.11.5/OgreBites and there is a command LC_ID_DYLIB with the name #executable_path/../Frameworks/OgreBites.framework/Versions/1.11.5/OgreBites, which matches the path given in the runtime error. However I don't know which step to take now as I have few experience with native library resolution on macOS.
Update:
Executing the command install_name_tool makes the linker find the library, but then it fails with the next one. I suppose/hope there is an option in CMake to pass it to the compiler so the binary files created during Ogre's compilation do not use the #execute_path directive?
I'm faced with the same problem, when using clion to build ogre in macos.
I found the symbolic links were invalid in the directory cmake-build-debug/bin/SampleBrowser.app/Contents/Frameworks.
I guess these symbolic links should point to
these frameworks int the cmake-build-debug/lib/macosx. So I modified the file where executed ln to create these symbolic links.
In the file Samples/Browser/CMakeLists.txt, change
set(OGRE_OSX_BUILD_CONFIGURATION "${CMAKE_OSX_SYSROOT}/$(CONFIGURATION)")
into
set(OGRE_OSX_BUILD_CONFIGURATION "macosx")
And clean and rebuild, then the problem will disappear.
A CMake project builds and runs tests OK on Linux and Windows, but running the test program fails on macOS.
dyld: Library not loaded: libfoo.dylib
Referenced from: /some/path/test_foo
Reason: image not found
I can verify that libfoo.dylib is in the same dir as the test program test_foo. Running ./test_foo works OK.
CMake calls test_foo via ctest (located in another path). Calling by ctest seems to be what makes it fail, but if I try a command like this (working dir being /some/path) it works:
DYLD_LIBRARY_PATH=`pwd` /another/path/ctest
I assume that running tests with add_test and ctest without setting DYLD_LIBRARY_PATH is possible since I can just run test_foo with success, but I haven't had luck.
Here are the current relevant contents of CMakeLists.txt
set(TEST_LIBS foo)
set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(test_foo tests/testfoo.cpp)
set_target_properties(test_foo PROPERTIES COMPILE_FLAGS "-DSELF_TEST")
target_link_libraries(test_foo ${TEST_LIBS} ${STUFF})
add_dependencies(build_tests test_foo)
add_test(NAME test_foo COMMAND $<TARGET_FILE:test_foo>
WORKING_DIRECTORY ${TEST_DIR})
I've tried setting/unsetting CMAKE_MACOSX_RPATH and MACOSX_RPATH before these lines, as suggested here:
I've tried adding the following snippet after the lines, as suggested here:
IF(APPLE)
SET(CMAKE_INSTALL_NAME_DIR ${TEST_DIR})
SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
ENDIF(APPLE)
I've not tried using install, I'm not sure how to configure that for my project or even what it does.
Any known approaches or any obvious mistakes here? Is install worth looking at? I want to be able to run the test from the CMake generated ctest line in the Makefile.
CMake 3.5.2, macOS 10.12.5
Solved as mentioned in comments, thanks to #Tsyvarev
Original comment pointing to the cause of the issue:
I can verify that 'libfoo.dylib' is in the same dir as the test program 'test_foo'. - Really? Your executable is created under binary tree, do you have the library there? If so, why do you use TEST_DIR as working directory or as a RPATH, while it points to source tree (tests subdirectory)?
I am trying to make a C++ program that uses the OpenSubdiv library from Pixar: https://github.com/PixarAnimationStudios/OpenSubdiv
I have managed to build the library, including the "tutorials", which uses the library.
Both OpenSubdiv and my own program is built with CMake (which I have some, but not much experince with). For testing purposes, I have a project folder where my C++ code lies, and I inside this folder I also have an OpenSubdiv folder where I have built the library in OpenSubdiv/build. The C++ code That I am using for testing purposes is identical to one of the tutorials provided by pixar with opensubdiv, called "far_tutorial_0.cpp". This tutorial compiles and work fine inside the Opensubdiv folder, with the very long and complex CMake script intended to install the entire library. However, when I move it out of the Opensubdiv folder, and try to compile with a simple CMake script, I get problems. This is the CMake script that I use:
cmake_minimum_required (VERSION 2.6)
project (test)
add_executable(test test.cpp)
include_directories(OpenSubdiv/build)
target_link_libraries(test osdCPU)
This manages to compile the code without any error messages, but when I try to execute the code, it says "error while loading shared libraries: libosdCPU.so.3.0.0.beta: cannot open shared object file: No such file or directory".
I have tried change the library name to "osdCPU.so.3.0.0.beta" (which gives an error while compiling), and I have tried using both library names (which gives the same error). The file "libosdCPU.so.3.0.0.beta" is inside the OpenSubdiv/build/lib folder, right next to "libosdCPU.so".
Does anybody know what's wrong?
You also have to provide the location of the library osdCPU with the CMake command link_directories.
Moreover, I encourage you to formalize your code with specific variables like this (including a cache variable you can modify through the command ccmake) :
set(osdCPU_PATH_DEFAULT "/default/path/to/osdCPU")
set(osdCPU_PATH "${osdCPU_PATH_DEFAULT}" CACHE PATH "Path to osdCPU")
set(osdCPU_INCLUDE_DIRS ${osdCPU_PATH}/include)
set(osdCPU_LIBRARY_DIRS ${osdCPU_PATH}/lib)
set(osdCPU_LIBRARIES osdCPU)
Then you can call
include_directories(${osdCPU_INCLUDE_DIRS})
link_directories(${osdCPU_LIBRARY_DIRS})
# ...
target_link_libraries(test ${osdCPU_LIBRARIES})
I have an external library here:
${PROJECT_SOURCE_DIR}/thirdparty/yaml-cpp/
It is made by a Makefile: thirdparty/Makefile. I am executing that makefile like so:
add_custom_target(
yaml-cpp
COMMAND make
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/thirdparty
)
I am then attempting to link the library, which builds to thirdparty/yaml-cpp/build/libyaml-cpp.a. This is the part that is not working:
target_link_libraries(load_balancer_node ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a)
I get the error:
Target "yaml-cpp" of type UTILITY may not be linked into another target.
One may link only to STATIC or SHARED libraries, or to executables with the
ENABLE_EXPORTS property set.
How do I execute that makefile and link the .a file?
So it makes sense that cmake can't figure out the dependencies here: it would have to parse the makefile and find the output. You have to tell it the output someone. Nearest I can figure, the best way to do this is to use a custom_command rather than a custom target:
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a
COMMAND make
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/thirdparty)
add_custom_target(
yaml-cpp
DEPENDS ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a)
...
add_dependencies(load_balancer_node yaml-cpp)
target_link_libraries(load_balancer_node ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a)
I was having linker troubles though (stupid windows machine), but cmake worked and made the libraries before trying to link.