c++cmakegoogletestldd

How can I point C++ tests to my build-directory copy of my library and not to the installed library when LD_LIBRARY_PATH points to the installed one?


I am working on a Project, which is installed by defining export LD_DIBRARY_PATH=.... My Problem is, that when I'm developing, the compiled test files linking to the installed library and not to the currently compiled library. My project is depended on another project inside my LD_DIBRARY_PATH, so I cannot unset the path for testing.

I found the following questions, however they could not help me:

I could reproduce this with the following example:

./CMakeLists.txt
./src/libA.cpp
./src/CMakeLists.txt
./include/libA.hpp
./test/test_libA.cpp
./test/CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.19)
project(
    LibraryTest
    VERSION 0.1
    LANGUAGES CXX)

add_subdirectory(src)

enable_testing()
add_subdirectory(test)

install(
    TARGETS ${PROJECT_NAME}Lib
    EXPORT ${PROJECT_NAME}Targets
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

install(
    EXPORT ${PROJECT_NAME}Targets
    FILE ${PROJECT_NAME}Targets.cmake
    NAMESPACE ${PROJECT_NAME}::
    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)

include/libA.hpp

#pragma one
bool foo();

src/CMakeLists.txt

add_library(
    ${PROJECT_NAME}Lib SHARED
    libA.cpp)

target_include_directories(
    ${PROJECT_NAME}Lib PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/>)

add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}Lib )

src/libA.cpp

#include "libA.hpp"

bool foo()
{
    return true;
}

test/CMakeLists.txt

# Download GTest
include(FetchContent)
option(INSTALL_GTEST "Enable installation of googletest." OFF)
FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest
    GIT_TAG v1.13.0)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)

# Add test
add_executable(test_libA test_libA.cpp)
target_link_libraries(
    test_libA
    ${PROJECT_NAME}::${PROJECT_NAME}
    GTest::gtest_main
    GTest::gtest
    GTest::gmock
    )
gtest_add_tests(TARGET test_libA)

test/test_libA.cpp

#include "libA.hpp"
#include <gtest/gtest.h>

TEST(libA, dummy)
{
    EXPECT_TRUE(foo());
}

int main(int argc, char *argv[])
{
    ::testing::InitGoogleTest(&argc, argv);
    auto result = RUN_ALL_TESTS();
    return result;
}

Building with cmake 3.22.1 and g++ 12.1.0:

mkdir build
cd build
cmake ..
make
make install

ldd results in the following output

ldd test/test_libA
libLibraryTestOut.so => $LD_LIBRARY_PATH/lib/libLibraryTestLib.so

Solution

  • so I cannot unset the path for testing

    Oh yes you can. Each process has its own environment (set of environment variables). You could set the LD_LIBRARY_PATH environment variable to a version with the path to your installed library is removed, or a version where your build-directory version of your library has a higher precedence (shows up earlier in the list) than the installed one.

    You can use your shell's mechanism for setting environment variables for a process (such as Bash, where you can set the variable at the start of the command line), or use your system's command for doing so (Ex. env), or use CMake's cross-platform alternative (cmake -E env), or if you're using CTest, use the ENVIRONMENT test property, or if you're additionally using CMake presets, use the environment field of a test preset.

    But the fact that you're using it for an installation in the first place is not great. Quoting from the Linux Documentation Project:

    LD_LIBRARY_PATH is handy for development and testing, but shouldn't be modified by an installation process for normal use by normal users; see "Why LD_LIBRARY_PATH is Bad" at http://www.visi.com/~barr/ldpath.html for an explanation of why. But it's still useful for development or testing, and for working around problems that can't be worked around otherwise.

    You could stop doing that and instead use other mechanisms of your system such as the PATH environment variable or RPATH.