Main / Cmake
CMake is a build system generation tool, so for example it creates your Makefiles for you if you use Make. Tutorial: https://cmake.org/cmake/help/latest/guide/tutorial/index.html#a-basic-starting-point-step-1 Note that newproject is the name of the executable that results, and newlib is the name of the library's folder. Think of CMake in execution as a line-by-line interpreted language, so things happen sequentially. For example, if you need a variable to be picked up by a subdir, it needs to be defined in your top level before the subdir is added. CMake defaults differ by platform: ConfigurationSet up your project in a CMakeLists.txt file. Here is a template for the file: # make cmake check the version in use cmake_minimum_required(VERSION X.X) # set the project name; note that if a language is not included here those files will be ignored project(newproject VERSION 1.0 LANGUAGES CXX C) # specify the C++ standard set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) #set(CMAKE_CXX_EXTENSIONS OFF) # other build options, like debug set(CMAKE_BUILD_TYPE Debug) # set compiler flags explicitly set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") # header with version number configure_file(newprojver.h.in newprojver.h) # point to the directory containing a library add_subdirectory(newlib) # add the executable add_executable(newproject newproject.cxx) # instruction to link to a library target_link_libraries(newproject PUBLIC newlib) # include file search path target_include_directories(newproject PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/newlib" ) In the library subdir, create this CMakeLists.txt: add_library(newlib libfile.cxx) This add_library creates a static library (.a) by default so if you want a shared dynamic lib you should put in the SHARED option to get .so files. After you create the build system, the compiler flags that have been set for you can be found in the build directory in CMakeFiles/<projectname>.dir/flags.make. UsageExecute these commands inside your build/ destination folder. First, you create the build system:
Note that CMake has no deep clean command for the build system, you just need to delete everything inside the build directory and it will re-create it all. Then, you issue commands to the build system:
If you want to see the variables, one way is to install and use the curses TUI version for the system generation step like so: ccmake -LH <sourcedir> Passing debug verbosity flag to Make# instead of cmake --build .; # use cmake --build . -- -d VERBOSE=1; Syntax, Patterns, CommandsVariables are referenced with ${VARNAME}. To print the variables you can use message( ${CMAKE_CURRENT_SOURCE_DIR} ) for example. Good discussion about variable scope here: https://www.mgaudet.ca/technical/2017/8/31/some-notes-on-cmake-variables-and-scopes INTERFACE vs PRIVATE vs PUBLIC includes: https://stackoverflow.com/questions/26243169/cmake-target-include-directories-meaning-of-scope You can pass along command line options to the underlying make system like this: cmake --build . -- <make-options-here> as in cmake --build . -- VERBOSE=1 -d If you are building two libraries for your program, and one depends on the other, then for the linking step to be carried out correctly you must tell CMake about this dependency. In the CMakeLists.txt for the needy library, add a target_link_libraries(thislib neededlib) command. Common Sequencescmake -DCMAKE_TOOLCHAIN_FILE=cross.cmake ../ cmake --build . EV Reference
Adding Docker to CMake# set up command line option for Docker image build here # invoked as "cmake -DBUILD_DIMAGE <path>" # expects Dockerfile to be at top level option(BUILD_DIMAGE "Build Docker image option" OFF) if (BUILD_DIMAGE) find_program(Docker_EXECUTABLE docker) if(NOT Docker_EXECUTABLE) message(FATAL_ERROR "Cannot find the docker executable!") endif() if(EXISTS ${CMAKE_SOURCE_DIR}/Dockerfile) string(APPEND dimagename "mycompany/${CMAKE_PROJECT_NAME}:${projectname_VERSION_MAJOR}.${projectname_VERSION_MINOR}" ) add_custom_target(docker_image ALL COMMAND echo "Building Docker image: ${dimagename}" COMMAND sudo ${Docker_EXECUTABLE} build -t ${dimagename} ${CMAKE_SOURCE_DIR} ) add_dependencies(docker_image projectname) else() message(FATAL_ERROR "Cannot find the Dockerfile!") endif() endif(BUILD_DIMAGE) unset(BUILD_DIMAGE CACHE) Adding Doxygen to CMake# set up command line option for Doxygen documentation generation here # invoked as "cmake -DDOXYGEN=ON <path>" # expects Doxyfile to be at top level option(DOXYGEN "Generate Doxygen documentation option" OFF) if (DOXYGEN) find_program(Doxygen_EXECUTABLE doxygen) find_program(Graphviz_EXECUTABLE dot) if(NOT Doxygen_EXECUTABLE) message(FATAL_ERROR "Cannot find the doxygen executable!") endif() if(NOT Graphviz_EXECUTABLE) message(FATAL_ERROR "Cannot find the graphviz-dot executable!") endif() if(EXISTS ${CMAKE_SOURCE_DIR}/Doxyfile) add_custom_target(doxygen ALL WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND echo "Generating documentation" COMMAND ${Doxygen_EXECUTABLE} ${CMAKE_SOURCE_DIR}/Doxyfile ) else() message(FATAL_ERROR "Cannot find the Doxyfile!") endif() endif(DOXYGEN) unset(DOXYGEN CACHE) Adding cppcheck to CMakeTo be inserted before add_executable() # set up command line option for cppcheck static analysis here # invoked as "cmake -DCPPCHECK=ON <path>" option( CPPCHECK "Run cppcheck static analysis" OFF ) if( CPPCHECK ) find_program( CPPCHECK_APP NAMES cppcheck PATH_SUFFIXES "" ".exe") # Run this if cppcheck found if ( NOT (${CPPCHECK_APP} STREQUAL "CPPCHECK_APP-NOTFOUND") ) set( CMAKE_CXX_CPPCHECK ${CPPCHECK_APP} ) list(APPEND CMAKE_CXX_CPPCHECK "--enable=warning" "--inconclusive" # "--force" "--inline-suppr" #"--suppressions-list=${CMAKE_SOURCE_DIR}/CppCheckSuppressions.txt" ) endif() else() message("NOTICE: cppcheck turned off") endif(CPPCHECK) unset(CPPCHECK CACHE) Set a C pre-processor definitionAdd the option and assignment to the cmake command line, like: cmake -DBUILD_CONNECT_TYPE=SDR_NET_CONNECT ../; Edit the CMakeLists.txt file of the module in which you need this definition, using the add_compile_definitions cmake command. if (NOT BUILD_CONNECT_TYPE) set(BUILD_CONNECT_TYPE SDR_NET_CONNECT) endif() message(STATUS "BUILD_CONNECT_TYPE={${BUILD_CONNECT_TYPE}}") add_compile_definitions(${BUILD_CONNECT_TYPE}) String literalsThis will work in your c++ source file: #define STRNAME "vbr0" static constexpr auto g_ethIFname = STRNAME; But this will not: CMakelists.txt add_compile_definitions(STRNAME="\"vbr0\"") C++ source: static constexpr auto g_ethIFname = STRNAME; Although in theory you can create a C pre-proc define in CMake with this method, there is a phantom unexplained problem with assigning that to a constexpr. Boost header-only library exampleWe don't even need to specify the library we want to use (like asio for example which has just header-only dependencies as of Boost 1.82 anyway). # make cmake check the version in use cmake_minimum_required(VERSION 3.16) # set the project name; note that if a language is not included here those files will be ignored project(boost_socket_test VERSION 1.0 LANGUAGES CXX C) # specify the C++ standard set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) #set(CMAKE_CXX_EXTENSIONS OFF) # other build options, like debug set(CMAKE_BUILD_TYPE Debug) # set compiler flags explicitly set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") # find Boost library message("Begin search for Boost") set(BOOST_ROOT "../boost_1_82_0") find_package(Boost REQUIRED) message(STATUS "Boost_FOUND: ${Boost_FOUND}") message(STATUS "Boost_VERSION: ${Boost_VERSION}") # add the executable add_executable(boost_socket_test main.cpp) # include file search path target_include_directories(boost_socket_test PUBLIC "${PROJECT_BINARY_DIR}" "${Boost_INCLUDE_DIRS}" ) Implicit Includes of Common FoldersCMake has an exclusion list that includes folders like the Linux headers at /usr/include/ such that if you try to add that folder explicitly using something like: include_directories("/usr/include") you'll find that when make spits out its g++ command that directory is NOT included in the -I headers location list. |