CMake's ctest: image not found (possible rpath issue) - c++

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

Related

dyld not loading Ogre library

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.

How to trigger CMake reconfiguration from a target?

I have the following setup:
- build/
- conanbuildinfo.cmake (generated)
- conanfile.py
- CMakeLists.txt
A conan command is ran before CMake, generating conanbuildinfo.cmake. This contains include paths etc. to be used during the compilation later. If I change the conanfile, I want to trigger conan again and a re-run of CMake from the generated ninja build. I have a script that can call conan and it updates everything properly. However, this happens after CMake was ran and even though conanbuildinfo was changed, CMake won't run once more. This causes ninja to "not see" the changes in the dependency graph, so it doesn't rebuild everything it has to rebuild. That means I have to run ninja twice to get everything to update. The way I trigger the reconfigure currently is like this:
set(DS_CONFIG_INDICATOR ${CMAKE_BINARY_DIR}/ds_configured)
add_custom_command(
DEPENDS ${PROJECT_SOURCE_DIR}/conanfile.py
OUTPUT ${DS_CONFIG_INDICATOR}
COMMAND ${CMAKE_COMMAND} -E env --unset=PYTHONPATH ${PYTHON_BINARY} ${PROJECT_SOURCE_DIR}/scripts/common/reconfigure.py ${DS_CONFIG_INDICATOR} ${PROJECT_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Checking if reconfigure is needed"
USES_TERMINAL
)
add_custom_target(ConanReconfigure
DEPENDS ${DS_CONFIG_INDICATOR}
)
Is there a way to trigger a reconfigure after this script was ran?
I tried using the following without any success:
CMAKE_CONFIGURE_DEPENDS
Running cmake from the reconfigure.py script
Touching the main CMakeLists.txt from the reconfigure.py script
Using execute_process to run the script
Why didn't execute_process work?
It seems to me like this should work if you use execute_process (not add_custom_command) to run conan/reconfigure.py before any of the CMake logic that depends on its output, combined with adding the input files of that command to CMAKE_CONFIGURE_DEPENDS.
Trying to run something before CMake won't work... but you don't need to do that, anyway. I think your problem is that you are trying to solve the wrong question. Instead, look at it as a) you want to run something during CMake's execution, and b) you want to re-run CMake if your "conanfile" changes. Re-running CMake will re-run conan.

CMake not building a library when added as a subdirectory

I added the xgboost library as a git submodule of my project and I'm trying to add it to cmake as a subdirectory. Unfortunately it's not working. A simple hello world project with the following CMakeLists.txt replicates the error that I'm getting.
cmake_minimum_required(VERSION 3.2)
project(foo)
add_subdirectory(xgboost)
add_executable(${PROJECT_NAME} foo.cpp)
target_link_libraries(${PROJECT_NAME} xgboost)
After building the library there is nothing in the xgboost/lib directory so I get the following error.
clang: error: no such file or directory:
'/Users/.../myproject/xgboost/lib/libxgboost.dylib'
I think that the problem is generated in their CMakeLists file since they have two different targets. Maybe cmake is choosing the wrong target but I'm not familiar enough with cmake to figure it out. The following code is from xgboost's CMakeLists.
# Executable
add_executable(runxgboost $<TARGET_OBJECTS:objxgboost> src/cli_main.cc)
set_target_properties(runxgboost PROPERTIES
OUTPUT_NAME xgboost
)
set_output_directory(runxgboost ${PROJECT_SOURCE_DIR})
target_link_libraries(runxgboost ${LINK_LIBRARIES})
# Shared library
add_library(xgboost SHARED $<TARGET_OBJECTS:objxgboost>)
target_link_libraries(xgboost ${LINK_LIBRARIES})
set_output_directory(xgboost ${PROJECT_SOURCE_DIR}/lib)
#Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
add_dependencies(xgboost runxgboost)
My questions in order of importance are:
Is there any way to fix it without modifying xgboost's CMakeLists.txt file?
Is it reasonable to try to add xgboost to my project as a git submodule?
Is there any reason cmake is not instructing to build the library?
Note: There were several edits to this question since I tried to narrow down the problem and to provide more information.
(I would love to ask for few things beforehand in the comment section, but I have too low reputation to do so, so I will just give it a shot ;))
I have few suspects, and one of them is ${CMAKE_SOURCE_DIR} of the submodule's root CMakeLists.txt. Although the paths are set properly when you run that CMakeLists.txt alone, cmake gets confused the moment you add it as your subdirectory. Have you looked into another directories for your output binaries?
First I would suggest testing this hypothesis, and then I would suggest writing similar, but separate CMakeLists.txt file for xgboost library, and then substitute it in the project temporarily. Unfortunately the CMakeLists.txt filename is hardcoded and there is no possibility to have two files of that kind in one directory; so it seems that the answer to 1) is, that you rather have to change the file.
For the 2): as long as it does not require huge additional logic in your CMakeLists.txt, it makes sense. Other viable option is to create an install target, which you can use to install your xgboost library locally (using CMAKE_INSTALL_PREFIX(doc) variable), and then add the installation path to your CMAKE_LIBRARY_PATH(doc).

Running Google test at build time with CMake generated system

My configuration has CMake 3.6, Visual Studio 2015 and latest Google test from GitHub. I add my unit tests through one of my cmake functions addGtest and do the build. After this I can run the test from my RUN_TESTS target or using ctrl + F5 in VS and works as expected.
The final goal is to run the unit tests at build time using the CMake dependency management. For now, as a first step, I have enhanced my function to create a custom_target (included the entire function, in case there are unforeseen issues in the working part), but not build it:
function (addGtest)
# vvvv this part works as explained vvvv #
set (optBOOLS)
set (optSINGLES EXE)
set (optLISTS DLL_LIST)
cmake_parse_arguments (myARGS
"${optBOOLS}" "${optSINGLES}" "${optLISTS}" ${ARGN})
# addExecutable is a function that adds target executables
set(myARGS_DLL_LIST gtest_main gtest "${myARGS_DLL_LIST}")
addExecutable (EXE ${myARGS_EXE} DLL_LIST ${myARGS_DLL_LIST} ${myARGS_UNPARSED_ARGUMENTS})
add_test (NAME ${myARGS_EXE} COMMAND ${myARGS_EXE} WORKING_DIRECTORY
${CMAKE_INSTALL_PREFIX}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/bin
) # so it can be run using ctest
# ^^^^ this part works as explained ^^^^ #
add_custom_target (${myARGS_EXE}.tgt DEPENDS ${myARGS_EXE}
COMMAND ${myARGS_EXE} --gtest_output="xml:${myARGS_EXE}.xml"
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/bin
)
endfunction (addGtest)
As expected when I perform the build, a new target, say, utMyTest.tgt is added to VS, but it is not built. Now when I build this new target by hand in VS, I expect that the test will be run. But it doesn't and gives the following error:
1> The filename, directory name, or volume label syntax is incorrect.
I tried providing full path to the COMMAND option, removing double quotes around --gtest_output value, but to no avail. On the other hand when I cd to the working directory in a command line window and invoke the exe, it works fine!!
The first question is how do I fix it to run the test by building this new target? After that, I plan to add_custom_target (${myARGS_EXE}.run) and add_dependencies (${myARGS_EXE}.run ${myARGS_EXE}.tgt). Would this then run the test whenever the exe changes? Or should I do something else? Thank you for your help.
Could not add so much details in the comment, hence this answer.
1. Answer to the original problem
Since I needed the configuration dependent path in the WORKING_DIRECTORY option of the add_custom_target command, but cannot pass generator expressions to it, the idea is to use the CMAKE_CFG_INTDIR variable so:
add_custom_target (${myARGS_EXE}.tgt
DEPENDS ${myARGS_EXE}
COMMAND ${myARGS_EXE} --gtest_output=xml:${myARGS_EXE}.xml
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${CMAKE_CFG_INTDIR}/bin
)
Now, when you build the above target, the unit test is run in the WORKING_DIRECTORY which is not entirely desirable, since that is the install directory for libs and exes. It would be really nice to ...
2. Run the unit test from its build directory
While, at the same time, picking up the DLL paths from within Visual Studio, and storing the Gtest generated .xml file in the build directory. This is the solution:
In CMake version 3.10 CMAKE_MSVCIDE_RUN_PATH property was added. In the project wide CMakeLists.txt, set(CMAKE_MSVCIDE_RUN_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_CFG_INTDIR}/bin) - thanks to this solution #3, we can appendPATH to point to our install directory. And then replace the above add_custom_target command with this:
add_custom_command (
TARGET ${myARGS_EXE} POST_BUILD
COMMAND ${myARGS_EXE} --gtest_output=xml:${myARGS_EXE}.xml
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
)
This solution avoids the mess of creating additional targets. Clearly only when myARGS_EXE is built, the unit test is run. Obviously myARGS_EXE's transitive dependency on other DLLs is covered also.
If you have other elegant solutions, please post.

Linking runtime library for test with cmake

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