Here is my directory tree
I implemented accident component which have to be a standalone library. Here is CMakeLists.txt for it
set (ACCIDENT accident)
file (GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
file (GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
add_library (${ACCIDENT} STATIC ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories (${ACCIDENT} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
add_subdirectory (test)
and that works fine. Now I am trying to use that library in note part which should be linked with accident. Especially the accident.hpp file should be visible in my IDE without doing things like this
#include "../../accident/include/accident.hpp"
and the code from accident.cpp should also be accessible. My attempts was similar to this one
set (MUSIC_NOTE music_note)
file (GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
file (GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
add_library (${MUSIC_NOTE} STATIC ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories (${MUSIC_NOTE}
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../accident/include"
)
target_link_libraries (${MUSIC_NOTE} accident)
add_subdirectory (test)
unfortunately, it does not work - accident.hpp header is not found. Do you know where I am doing a mistake?
EDIT
In response to #Martin's question, here is my top level CMakeLists.txt
cmake_minimum_required (VERSION 3.5)
set (CMAKE_BUILD_TYPE Debug)
set (PROJECT_NAME scales)
project (${PROJECT_NAME} LANGUAGES CXX)
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set (CMAKE_MODULE_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_MODULE_PATH}")
set (CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_PREFIX_PATH}")
add_subdirectory (src)
add_subdirectory (external)
option (BUILD_TESTS "Build tests" ON)
enable_testing ()
if (BUILD_TESTS)
add_subdirectory (test)
endif ()
# Add google test
include (FetchContent)
FetchContent_Declare (
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
The note directory is in src, and src includes CMakeLists.txt with only one line
add_subdirectory (note)
In this note directory we have the stuff I pasted above Top level CMakeLists.txt in note directory contains
add_subdirectory (accident)
add_subdirectory (note)
EDIT 2
Problem resolved - see Ave Milia comment below. Thanks!
As we figured out in the comment section, the test executable was forgotten to be linked to the relevant static library.
Related
I want to build my C++ project with CMake and I want to include automatically every new file on "cmake ." my project structure is:
Application/ Graphics/ CMakeLists.txt CMakeLists.txt.user main.cpp
./Application:
CMakeLists.txt Logger/ Recovery/ application.cpp application.hpp firstclass.cpp firstclass.hpp singleton.hpp
./Application/Logger:
CMakeLists.txt logger.cpp logger.hpp
./Application/Recovery:
CMakeLists.txt recovery.cpp recovery.hpp
./Graphics:
CMakeLists.txt drawableobject.cpp drawableobject.hpp graphics.cpp graphics.hpp
Each folder has own CMakeLists.txt
I did so far this in master CMake:
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Asteri VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
message("Source dir: ${SOURCE_DIR}")
#file(GLOB_RECURSE SRC_FILES ${SOURCE_DIR}/*.cpp)
#file(GLOB_RECURSE HEADER_FILES ${HEADER_DIR}/*.hpp)
set(PROJECT_NAME "Asteri")
macro(SUBDIRLIST result curdir)
file(GLOB children RELATIVE ${curdir} ${curdir}/*)
set(dirlist "")
foreach(child ${children})
if(IS_DIRECTORY ${curdir}/${child})
list(APPEND dirlist ${child})
endif()
endforeach()
set(${result} ${dirlist})
endmacro()
SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR})
foreach(subdir ${SUBDIRS})
message("Subdirectory: ${subdir}")
add_subdirectory(${subdir})
endforeach()
add_executable(${Asteri} main.cpp)
The question is how to connect all pieces together?
What I need in other CMakeLists.txt?
How to communicate children -> parent or I misunderstood the concept of CMake?
No need for other CMakeLists.
I guess you want something like this in top CMakeLists:
cmake_minimum_required(VERSION 3.12)
project(Asteri VERSION 1.0)
file(GLOB_RECURSE ASTERI_SRC_FILES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/Application/*.cpp"
"${PROJECT_SOURCE_DIR}/Graphics/*.cpp"
)
add_executable(Asteri main.cpp ${ASTERI_SRC_FILES})
It's worth noting that GLOB/GLOB_RECURSE -even with CONFIGURE_DEPENDS- is bad practice: it's slow, specially on Windows from my experience, and may not work as expected depending on generator used.
I found out the answer to my problems.
set(SOURCES "${PROJECT_DIR}/main.cpp" CACHE INTERNAL STRINGS)
add_subdirectory(application)
FOREACH(it ${SOURCES})
message("source file: ${it}")
ENDFOREACH()
add_executable(Asteri ${SOURCES})
In this way I store main.cpp path into variable SOURCES
You can see your variables after 'make' in CMakeCache.txt.
After this is done, my variable SOURCES looks like:
/STRINGS
SOURCES:INTERNAL=/home/default/cpp_testing_project/cmake_project/source/main.cpp;
After that in application subdirectory I have CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
# Get source files
file(GLOB CPP_LIST "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
set(SOURCES ${SOURCES} ${CPP_LIST} CACHE INTERNAL STRINGS)
And now SOURCES looks like:
SOURCES:INTERNAL=/home/default/cpp_testing_project/cmake_project/source/main.cpp;/home/default/cpp_testing_project/cmake_project/source/application/application.cpp;/home/default/cpp_testing_project/cmake_project/source/application/drawableobject.cpp;/home/default/cpp_testing_project/cmake_project/source/application/firstclass.cpp;/home/default/cpp_testing_project/cmake_project/source/application/graphics.cpp;/home/default/cpp_testing_project/cmake_project/source/application/application.hpp;/home/default/cpp_testing_project/cmake_project/source/application/drawableobject.hpp;/home/default/cpp_testing_project/cmake_project/source/application/firstclass.hpp;/home/default/cpp_testing_project/cmake_project/source/application/graphics.hpp;
The project structure of my static library is exactly the same as defined in this question and my CMakeList.txt is exactly the same:
cmake_minimum_required (VERSION 2.8)
project (project_name)
add_subdirectory (src)
add_subdirectory (test)
I want to build the test folder after my static library. I have also added add_test() but only problem is my test directory doesn't contain unit tests, but actual test application like following code:
#include <iostream>
main() {
/*
this code uses static library functions in it. There is not Unit Test defined in it.
*/
}
add_test() didn't helped me, and I am still getting a cannot find -ldal error. dal is my static library name, which I have added as target_link_library to my test application.
libdal/src/CMakeList.txt
cmake_minimum_required(VERSION 3.12)
project(dal)
# Flags Variables
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
# Include Directeries
include_directories(${CPP_KAFKA_INC})
include_directories(${CPP_MYSQL_INC})
include_directories(${CPP_ALTIBASE_INC})
include_directories(${AFN_STATE_INC})
include_directories(${AFN_DAL_INC})
include_directories(${AFN_COMMONS_INC})
include_directories(${AFN_CONFIG_INC})
include_directories(${SQL_ODBC_INC})
# Executable Target(s)
file(GLOB SOURCES *.cpp)
add_library(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME}
${AFN_LIB}
"-lafinit_state"
"-luuid"
"-lz"
"-lpthread"
${PQXX_LIB}
${PQ_LIB}
"-lmysqlcppconn"
${libmscpp}
${kafkacpplib}
${rdkafkalib}
${rdkafkacpplib}
afiniti_config $<$<CONFIG:DEBUG>:-lgcov>
)
# Installation
install(CODE "MESSAGE(\"Installing ${PROJECT_NAME} \")")
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
libdal/test/CMakeList.txt
cmake_minimum_required(VERSION 3.12)
project(testdal)
# Flags Variables
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17" )
option(DAL_PUSH_TESTER "enable DAL push tester" ON)
# Include Directeries
include_directories(${CPP_KAFKA_INC})
include_directories(${AFN_DAL_INC})
include_directories(${CPP_MYSQL_INC})
include_directories(${AFN_STATE_INC})
include_directories(${AFN_CONFIG_INC})
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME}
${AFN_LIB}
"-lmysqlcppconn"
"-luuid"
"-lz"
${libmscpp}
"-ldal"
${PQXX_LIB}
${PQ_LIB}
${kafkacpplib}
${rdkafkalib}
${rdkafkacpplib}
"-lafinit_state"
"-luuid"
"-lpthread"
afiniti_config $<$<CONFIG:DEBUG>:-lgcov>
${AFN_LICENSE_LIB} "-laf_license_manager"
)
# Installation
install(CODE "MESSAGE(\"Installing ${PROJECT_NAME} \")")
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin/tests
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
if (DAL_PUSH_TESTER)
add_executable(dal_push_tester dal_push_tester.cpp)
target_link_libraries(dal_push_tester
${AFN_LIB}
"-lmysqlcppconn"
"-luuid"
"-lz"
${libmscpp}
"-ldal"
${PQXX_LIB}
${PQ_LIB}
${kafkacpplib}
${rdkafkalib}
${rdkafkacpplib}
"-lafinit_state"
"-luuid"
"-lpthread"
afiniti_config $<$<CONFIG:DEBUG>:-lgcov>
${AFN_LICENSE_LIB} "-laf_license_manager"
)
# Installation
install(CODE "MESSAGE(\"Installing dal_push_tester \")")
install(TARGETS dal_push_tester
RUNTIME DESTINATION bin/tests
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
endif ()
The issue has been raised a couple times on the site, but there are some other issues with your CMake file that warrant explanation.
The problem is that the linker doesn't know where to find the dal library, because you've only provided "-ldal", without a full path to the library or anything. You can fix this by simply using the CMake library target name (dal) in target_link_libraries() instead, because it was defined earlier in the same CMake invocation.
target_link_libraries(${PROJECT_NAME}
${AFN_LIB}
"-lmysqlcppconn"
"-luuid"
"-lz"
${libmscpp}
dal # <------ Note the change on this line.
${PQXX_LIB}
${PQ_LIB}
${kafkacpplib}
${rdkafkalib}
${rdkafkacpplib}
"-lafinit_state"
"-luuid"
"-lpthread"
afiniti_config $<$<CONFIG:DEBUG>:-lgcov>
${AFN_LICENSE_LIB} "-laf_license_manager"
)
Furthermore, target_link_libraries doesn't need the explicit -l link flag added; it adds this automatically. Also, you should always specify the scoping argument (e.g. PRIVATE, PUBLIC, etc.) for this and other target_* calls. Also, also, you have linked uuid twice, so you can probably remove one of these:
target_link_libraries(${PROJECT_NAME} PRIVATE
${AFN_LIB}
mysqlcppconn
uuid
z
${libmscpp}
dal
${PQXX_LIB}
${PQ_LIB}
${kafkacpplib}
${rdkafkalib}
${rdkafkacpplib}
afinit_state
pthread
afiniti_config $<$<CONFIG:DEBUG>:gcov>
${AFN_LICENSE_LIB} af_license_manager
)
In addition, the manual modification of CMAKE_CXX_FLAGS in this line:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
is highly discouraged. For setting the C++ standard, you should use:
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
or one of the other more modern approaches discussed in this question.
I encourage you to browse through some of the content regarding modern CMake practices.
First of all, I know there are very similar questions in this forum. However, none really answer my specific case.
I have the following project structure:
|---Project_Root
|---CMakeLists.txt
|---build
|---src
| |---CMakeLists.txt
| |---many .cpp and .h files in multiple subfolders with a different CMakeLists.txt
|---tests
| |---CMakeLists.txt
| |---many .cpp files
In the Project_Root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(SRC_DIR src)
project(
Project
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} "")
target_include_directories(${PROJECT_NAME} PRIVATE ${SRC_DIR})
add_subdirectory(${SRC_DIR})
In the src folder and subfolder CMakeLists.txt files:
cmake_minimum_required(VERSION 3.5)
set(SRC_FILES
Source1.cpp
)
set(HEADER_FILES
Source1.hpp
)
target_sources(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILES}
)
Now in the tests subfolder:
project(Test LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
enable_testing()
add_executable(Test tst_test.cpp)
add_test(NAME Test COMMAND Test)
target_link_libraries(Test PRIVATE Qt5::Test)
In the above CMakeLists.txt I want to include the main project as a static library. I can, for example, add a new library target (say Project_Lib) in the root CMakeLists.txt and use once again the command:
target_sources(Project_Lib
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILES}
)
in all the subfolders.
But is there a more elegant way of doing it without having to modify all the CMakeLists.txt in the subfolders? For example, is there way to extract the source files from the Project target, so that it can be reused to make the Project_Lib target?
As you described, you can make a new static library target Project_Lib. Take advantage of the fact that you parameterized the target name by using the project name (${PROJECT_NAME}), so you actually don't have to change all of the CMakeLists.txt files in the subfolders. Just change the project name.
As I commented, simply exclude the main.cpp file from the static library, and add it to a separate executable target instead.
In Project_Root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(SRC_DIR src)
# Change the project name, as now the static library is the primary target.
project(
Project_Lib
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Create the static library target, whose sources are populated in subdirectories.
add_library(${PROJECT_NAME} STATIC)
target_include_directories(${PROJECT_NAME} PRIVATE ${SRC_DIR})
# The only modification necessary in the subdirectories is to *exclude* the
# main.cpp file from the target_sources for the static library.
add_subdirectory(${SRC_DIR})
# Add *only* the main.cpp file to the executable target.
add_executable(Project_Exe src/main.cpp)
# Link the static library target to the executable.
target_link_libraries(Project_Exe PRIVATE ${PROJECT_NAME})
In tests/CMakeLists.txt:
...
# Link the static library to your Test executable also.
target_link_libraries(Test PRIVATE Project_Lib Qt5::Test)
I am building a medium sized C++ library, and my CMakeLists.txt file is starting to get a bit long. I was reading Robert Martin's book The Clean Coder in which he discusses the elements of clean coding style for the sake of code maintenance and readability.
So I wanted to see if I could break up my CMakeLists.txt file into a set of smaller files--that would integrate when I ran a build command. I could then just manage these smaller files, just as I would break up classes into separate files. Now as a caveat, I am not building separate executables for different elements of the library. I am just building a single library with a set of classes and functions that I need for other projects.
Here is my current CMakeLists.txt file. Then I will show how I would like to break it up.
cmake_minimum_required(VERSION 3.7)
project(tvastrCpp)
set (tvastrCpp_VERSION_MAJOR 0)
set (tvastrCpp_VERSION_MINOR 1)
# Find CGAL
find_package(CGAL REQUIRED COMPONENTS Core) # If the dependency is required, use REQUIRED option - if it's not found CMake will issue an error
include( ${CGAL_USE_FILE} )
include(ExternalProject)
set(CMAKE_CXX_STANDARD 14)
find_package(Eigen3 3.1.0)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
find_package(Boost 1.58.0 REQUIRED COMPONENTS system filesystem program_options chrono timer date_time REQUIRED)
if(NOT Boost_FOUND)
message(FATAL_ERROR "NOTICE: This demo requires Boost and will not be compiled.")
endif()
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
ExternalProject_Add(
catch
PREFIX ${CMAKE_BINARY_DIR}/catch
GIT_REPOSITORY https://github.com/philsquared/Catch.git
TIMEOUT 10
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
ExternalProject_Get_Property(catch source_dir)
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
INCLUDE_DIRECTORIES ( "${EIGEN3_INCLUDE_DIR}" )
file(GLOB lib_SRC RELATIVE "lib" "*.h" "*.cpp")
file(GLOB test_SRC RELATIVE "tests" "*.h" "*.cpp")
# need to fix the instruction below to reference library
set(SOURCE_FILES ${lib_SRC})
add_library(tvastrCpp SHARED ${SOURCE_FILES})
add_executable(${PROJECT_NAME} main.cpp random_mat_vector_generator.h random_mat_vector_generator.cpp)
add_executable(my_tests testcases.cpp RipsComplex.h RipsComplex.cpp random_mat_vector_generator.h random_mat_vector_generator.cpp)
add_executable(gd_validator gudhi_validator.cpp)
TARGET_LINK_LIBRARIES( gd_validator ${Boost_LIBRARIES} )
enable_testing(true)
add_test(NAME cooltests COMMAND my_tests)
Now I would like to create a separate file for the basic settings piece:
settings.txt:
cmake_minimum_required(VERSION 3.7)
project(tvastrCpp)
set (tvastrCpp_VERSION_MAJOR 0)
set (tvastrCpp_VERSION_MINOR 1)
Then a separate piece for the finding the CGAL library:
find_cgal.txt:
find_package(CGAL REQUIRED COMPONENTS Core) # If the dependency is required, use REQUIRED option - if it's not found CMake will issue an error
include( ${CGAL_USE_FILE} )
include(ExternalProject)
set(CMAKE_CXX_STANDARD 14)
find_package(Eigen3 3.1.0)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
And so forth.
Split your CMakeLists.txt into:
Project's top file:
Contains all common settings of the project
Includes the external projects
Include the sub directories
Set the common compiler settings
Builds the targets
Reusable functions file:
Store your own CMake macros and functions into a separate file to reuse it in your different projects
Source files:
Place a CMakeList.txt in every subdirectory of source code
Add the sources here to the variable SOURCE and use PARENT SCOPE
Tests:
Use a extra CMakeLists.txt to build the unit tests
Reuse the previous structure of CMake files in case of large test environment
I have small projects with one CMakeLists.txt and large projects for a single library with up to 10 files.
My program uses giblib and Imlib2 library and it is built with cmake.
It works perfectly in my computer but not in other's.
I guess the reason is I installed every library what my program needs but other's doesn't.
My goal is making standalone program. (don't need to install any other library addtionally)
What should I add in cmake file?
projectDef.cmake source code
file (GLOB PLATFORM RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
X11/[^.]*.cpp
X11/[^.]*.h
X11/[^.]*.cmake
)
SOURCE_GROUP(X11 FILES ${PLATFORM})
add_definitions(
)
set (SOURCES
${SOURCES}
${PLATFORM}
)
add_x11_plugin(${PROJECT_NAME} SOURCES)
target_link_libraries(${PROJECT_NAME}
${PLUGIN_INTERNAL_DEPS}
)
include_directories(/usr/include/giblib)
include_directories(/usr/include/X11)
target_link_libraries(MyProject X11)
target_link_libraries(MyProject Imlib2)
target_link_libraries(MyProject giblib)
CMakeList.txt source code
cmake_minimum_required (VERSION 2.6)
set (CMAKE_BACKWARDS_COMPATIBILITY 2.6)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "-static")
Project(${PLUGIN_NAME})
file (GLOB GENERAL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
[^.]*.cpp
[^.]*.h
[^.]*.cmake
)
include_directories(${PLUGIN_INCLUDE_DIRS})
SET_SOURCE_FILES_PROPERTIES(
${GENERATED}
PROPERTIES
GENERATED 1
)
SOURCE_GROUP(Generated FILES
${GENERATED}
)
SET( SOURCES
${GENERAL}
${GENERATED}
)
include_platform()
Try starting with this options in your root CMakeLists.txt:
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
BUILD_SHARED_LIBS is only needed if your project has its own libraries (add_library).
With the -static linker flag, you need static libs for ALL your additional libraries too! One common problem when static linking is to avoid circular dependencies.