Make some library's code private some consumers, but public for tests

Hello,

I made a library project, and followed the classical pattern, where I put the implementation details in a src directory, and the interface in a include/MyLib directory.
So the external consumers see what is exposed in the latter, and link to the sources compiled from the former.

But what about the unit tests ? How could I make them access to the implementation details ? I mean free functions and public member functions which are not exposed to the “normal consumers”.

You could do something like this:

target_include_directories(libtgt
  INTERFACE
    "$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:tests_libtgt>>:path/to/internal/headers>>")
# …
set_property(PROPERTY test_target_for_libtgt
  PROPERTY tests_libtgt 1)

This:

  • makes it happen only for the build tree
  • asks the linking target for its tests_libtgt property
  • if it is “true”, adds the path for includes

OK, thank you, I’ll try that !

PS: I thought I lost my message, so I opened an other subject…

If developing on Windows (or linux etc with default visibility to false), then remember to export all the functions that you want available for testing too.

In our codebase, we have 3 include folders - public, private, and protected. Public gets shipped, protected is available to the tests but not shipped, and private stays private.

The alternative to this solution, which we considered but rejected for now, is to create an Object library target of the code that you want to expose to tests, but not make public in your library. That way, you could link that object library against your tests and your lib both. But we didn’t like the idea of splitting our lib into multiple artificial targets, hence going for the public/private/protected headers.

What buildsystem design techniques are there (using CMake) to test functionality that is internal to my shared library?

Sorry for reacting so late.
Here is what I finally have done.

My project has three directories :

  • include/MyLibrary
  • src
  • test

The first one contains the public interface.
The second one contains the sources (private .h + all .cpp)

The src and test directories has their own CMakeLists.txt, and there is an other CMakeLists.txt in the root directory.

The CMakeLists.txt from the src directory is called at the first place, and it builds a target called MyLib.
The CMakeLists.txt from the test directory is called afterwards, and it is linked to this target.

Each directory has its own command target_include_directories().
The one in the test directory is :

target_include_directories(MyLibTest
    PRIVATE
        ${PROJECT_SOURCE_DIR}/include
        ${PROJECT_SOURCE_DIR}/src)

The CMakeLists.txt in the src directory contains the following command :

target_include_directories(MyLibrary
    PUBLIC
        $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    PRIVATE
        ${CMAKE_CURRENT_LIST_DIR})

I can’t remember why I did that, but it does work as I wish : the private .h are hidden from the installed files, and a re visible from the tests.

so all your inplementation is in your headers?