Reputation: 1627
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.
Edit:
CMakelists.txt
files to use absolute paths only (as per recommendation from @TsyvarevOriginal 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:
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 libraryWhat 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
Upvotes: 1
Views: 1965
Reputation: 141940
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.
Upvotes: 3