Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

CMake – Library with example subdirectory running as separate project

Edit 2 – Fixed!

The issue was fixed by correctly using absolute paths rather than relative paths, and by adding add_subdirectory to example/CMakelists.txt.

I have updated the provided code (and will leave the repository in case somebody wants to use it as a starting point.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Edit:

  • Adjusted CMakelists.txt files to use absolute paths only (as per recommendation from @Tsyvarev
  • Added exact compilation error message

Original post:

I am trying to write a library, that contains example project, and can be added as a Git submodule. The desired structure would be this:

- source
  - MyLib
    lib.cpp
  - CMakelists.txt
- include
  - MyLib
    lib.h
- example
  main.cpp
  CMakelists.txt
CMakelists.txt (main CMake for library)

What am I trying to achieve:

  • The structure should probably more or less stay, so one can install the library just by adding a gitmodule
  • The example project should be capable of running on its own by loading the CMakelists.txt in the directory, and should be able to use the library

What is my problem:
My biggest problem is linking the example to the library which lives in a sibling folder, and make sure it compiles. I managed to write a CMakelists.txt in a way that my IDE understands #include statements correctly, but during compilation the function definitions are not found.
Could anyone provide some pointers, please?

Exact compilation error message:

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lMY_LIB
collect2.exe: error: ld returned 1 exit status
mingw32-make[3]: *** [CMakeFiles\MY_LIB_EXAMPLE.dir\build.make:95: MY_LIB_EXAMPLE.exe] Error 1
mingw32-make[2]: *** [CMakeFiles\Makefile2:82: CMakeFiles/MY_LIB_EXAMPLE.dir/all] Error 2
mingw32-make[1]: *** [CMakeFiles\Makefile2:89: CMakeFiles/MY_LIB_EXAMPLE.dir/rule] Error 2
mingw32-make: *** [Makefile:123: MY_LIB_EXAMPLE] Error 2

CMakelists.txt files
CMakelists.txt:

cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 20)
project(MY_LIB)
add_subdirectory(source)

source/CMakelists.txt

add_library(MY_LIB MyLib/library.cpp ../include/MyLib/library.h)

target_include_directories(MY_LIB PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/MyLib)
target_include_directories(MY_LIB PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/source/MyLib)

example/CMakelists.txt

cmake_minimum_required(VERSION 3.20)

set(CMAKE_CXX_STANDARD 20)

#--------------------------------------------------------------------
# Get solution root
#--------------------------------------------------------------------
cmake_path(GET CMAKE_CURRENT_SOURCE_DIR PARENT_PATH LIB_PATH)
cmake_path(SET LIB_INCLUDE_PATH "${LIB_PATH}/include")

message(${LIB_PATH})
message(${LIB_INCLUDE_PATH})

#--------------------------------------------------------------------
# Set project name
#--------------------------------------------------------------------
project(MY_LIB_EXAMPLE)

#--------------------------------------------------------------------
# Add source
#--------------------------------------------------------------------
add_executable(MY_LIB_EXAMPLE main.cpp)
add_subdirectory(${LIB_PATH} library-build)

#--------------------------------------------------------------------
# Link libraries
#--------------------------------------------------------------------
target_link_libraries(MY_LIB_EXAMPLE MY_LIB)

#--------------------------------------------------------------------
# Link include directories
#--------------------------------------------------------------------
target_include_directories(MY_LIB_EXAMPLE PUBLIC ${LIB_INCLUDE_PATH})

I created a sample repository with my setup: https://github.com/jiriKralovec/cmake-library

>Solution :

he example project should be capable of running on its own by loading the CMakelists.txt in the directory, and should be able to use the library

Just add:

add_subdirectory(./../ some_unique_name_here)

I think I would remove source/CMakelists.txt and write it all in root CMakelists.txt. It’s odd to use ../ to refer to include directories.


I suggest doing options and/or unit tests:

root CMakeLists.txt:

include(CTest)
add_library(MY_LIB ....)

# one design
if (BUILD_TESTING)
   add_subdirectory(example)
endif()

# another design
add_subdirectory(utilities)

example/CMakeLists.txt:

# if it is something simple, add unit test:
add_executable(MY_LIB_EXAMPLE1 <maybe EXCLUDE_FROM_ALL?> ...)
add_test(NAME MY_LIB_EXAMPLE1 COMMAND MY_LIB_EXAMPLE1)

utilities/CMakeLists.txt:

# if it is a utility, optionally build it
add_executable(MY_LIB_UTILITY_TO_DO_SMTH ...)
option(... BUILD_MY_LIB_UTILITY_TO_DO_SMTH OFF)
if(NOT BUILD_MY_LIB_UTILITY_TO_DO_SMTH)
   set_target_properties(
       MY_LIB_UTILITY_TO_DO_SMTH
       PROPERTIES EXCLUDE_FROM_ALL ON
   )
endif()

Either way, do one CMake build. Then if user wants to build the utility, he will do cmake --build <builddir> --target MY_LIB_UTILITY_TO_DO_SMTH (or make MY_LIB_UTILITY_TO_DO_SMTH). If you would want to build unit tests, you would do cmake ... -D BUILD_TESTING=1.

Some people add all unit tests executables as EXCLUDE_FROM_ALL and make special add_custom_target(build_tests) add_target_dependencies(build_tests MY_LIB_EXAMPLE1 etc. etc.) and build that custom target before testing.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading