how to use CMake file (GLOB SRCS *. ) with a build directory - cmake

this is my current CMakeLists.txt file
cmake_minimum_required(VERSION 3.3)
set(CMAKE_C_FLAGS " -Wall -g ")
project( bmi )
file( GLOB SRCS *.cpp *.h )
add_executable( bmi ${SRCS})
This builds from my source directory, but I have to clean up all the extra files after. My question is how do I build this from a build directory if all my source files are in the same source directory?
thanks

If you really need to use file(GLOB …), this CMakeLists.txt should work :
cmake_minimum_required(VERSION 3.3)
project(bmi)
add_definitions("-Wall" "-g")
include_directories(${PROJECT_SOURCE_DIR})
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
add_executable(bmi ${SRC_FILES})
In this case you have to launch cmake from your build directory every time you add or delete a source file :
cmake <your_source_dir> -G <your_build_generator>
As Phil reminds, CMake documentation doesn't recommend this use of GLOB. But there are some exceptions. You'll get more information on this post.
If you don't meet those exceptions, you'd rather list your source files than use GLOB :
set(SRC_FILES ${PROJECT_SOURCE_DIR}/main.cpp
${PROJECT_SOURCE_DIR}/bmi.cpp
… )
NB : if you have #include of your .h files in .cpp files, I don't see any reason to put them in add_executable, you just need to specify include directory with include_directories.

Cmake used to only update the list of source files if CMakeLists.txt was changed since the last cmake run or if cmake was used to configure the project again.
In cmake 3.11.0 recursive search and automatic re-configuration on adding or deleting source files was added. Since then you can use the following snippet:
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0")
file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp *.h)
else()
file(GLOB SOURCE_FILES *.cpp *.h */*.h */*.cpp)
endif()
The file() command after the else() provides at least a bit of backwards compatibility: It still searches for source files in the current folder and its direct subfolders. But it doesn't automatically recognize if there are new files or old files have been deleted.
Note that VERSION_GREATER_EQUAL is only available in cmake >= 3.7

Related

CMake How to access headers and source files in a different folder

I have a code repository like image below. I'm trying to add a new standalone executable. The main.cpp and CMakeLists.txt files are located in folder4 and main.cpp requires code from folder3.
At the moment I'm using:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(Standalone)
# add the executable
add_executable(StandaloneExe main.cpp)
Should I now use file( GLOB SRCS *.cpp *.h ) to retrieve the headers and source files from folder3?
I just want the simplest way of generating this executable.
Should I now use file( GLOB SRCS *.cpp *.h ) to retrieve the headers and source files from folder3?
No, you should never use GLOB to get sources. See my answer here for more detail: https://stackoverflow.com/a/65191951/2137996
I just want the simplest way of generating this executable.
Put your CMakeLists.txt in the root instead. Then just write:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(Standalone)
# add the executable
add_executable(
StandaloneExe
folder2/folder4/main.cpp
folder1/folder3/a.cpp
folder1/folder3/b.cpp
)
# Might need this, maybe not, depending on your includes
target_include_directories(
StandaloneExe
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/folder1/folder3"
)
If you absolutely cannot move your lists file, then you can use absolute paths:
add_executable(
StandaloneExe
${CMAKE_CURRENT_LIST_DIR}/../../folder2/folder4/main.cpp
${CMAKE_CURRENT_LIST_DIR}/../../folder1/folder3/a.cpp
${CMAKE_CURRENT_LIST_DIR}/../../folder1/folder3/b.cpp
)

CMake protobuf external to application code

Basically, I want to have my structure like such:
MainRepo
+---app1
+---app2
+---common
+---some_lib1
+---some_lib2
+---protobuf
+---comms.proto
+---cs
+---Comms.pb.cs
+---cpp
+---comms.pb.cc
+---comms.pb.h
I want to be able to check out the repo and have a script that runs protoc for all the different languages for the apps that are in the repo. This is a mono repo containing an app for two different arm machines and an x64. I essentially are running protoc and it generates all the source files for c, js, cs, cpp, etc and puts them under protobuf in their own folders.
I want to have app1, for example, go find the c++ header and source and use them to build the app. At the moment, the example I have been hacking, uses cmake to generate the .cc and .h which makes it inconvenient for me as intellisense complains since those files dont exist when I'm writing.
Anyway, I've been hacking away at cmake all day. I always end up with cmake having a forward declaration error and cant compile my .cc and .h
PROJECT(test)
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")
ADD_EXECUTABLE(main main.cpp)
TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})
find_package(Protobuf REQUIRED)
set(PROTOBUF_IMPORT_DIRS "../proto")
set (msgs ${PROTOBUF_IMPORT_DIRS}/communications.proto)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${msgs})
add_library(proto SHARED ${PROTO_SRCS})
target_link_libraries(proto ${PROTOBUF_LIBRARY})
Wondering if there are any suggestions. I dont want to have my protobuf stuff outside of my common folder and I also dont need protoc to generate those files either as I do that another way (although I could change that way). I just want to ensure that the language specific files are still available to view and not just generated during cmake and I cant view them.
My 2 cents,
Here this is what I did for google/or-tools
ref: https://github.com/google/or-tools
Protobuf Integration
I'm using Fetchcontent() (CMake >= 3.18 to have SOURCE_SUBDIR option IIRC), but I also need to patch it (e.g. to have CMP0077)
you can find the protobuf patch here: https://github.com/google/or-tools/blob/stable/patches/protobuf-v3.12.2.patch
cmake/dependencies/CMakeLists.txt
include(FetchContent)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BUILD_TESTING OFF)
message(CHECK_START "Fetching Protobuf")
list(APPEND CMAKE_MESSAGE_INDENT " ")
set(protobuf_BUILD_TESTS OFF)
set(protobuf_BUILD_EXPORT OFF)
set(protobuf_MSVC_STATIC_RUNTIME OFF)
# FetchContent_Declare(SOURCE_SUBDIR) was introduced in 3.18
FetchContent_Declare(
protobuf
GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
GIT_TAG "v3.12.2"
PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.12.2.patch"
SOURCE_SUBDIR cmake)
FetchContent_MakeAvailable(protobuf)
list(POP_BACK CMAKE_MESSAGE_INDENT)
message(CHECK_PASS "fetched")
ref: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dependencies/CMakeLists.txt#L142-L168
note: for cmake < 3.18, I use ExternalProject + execute_process()
see: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/utils.cmake#L66-L137
Generate Protobuf files
Since we have integrated Protobuf, now we have access to protobuf::protoc.
To build proto file, simply adapt
# Get Protobuf include dirs
get_target_property(protobuf_dirs protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir IN LISTS protobuf_dirs)
if ("${dir}" MATCHES "BUILD_INTERFACE")
message(STATUS "Adding proto path: ${dir}")
list(APPEND PROTO_DIRS "--proto_path=${dir}")
endif()
endforeach()
# Generate Protobuf cpp sources
set(PROTO_HDRS)
set(PROTO_SRCS)
file(GLOB_RECURSE proto_files RELATIVE ${PROJECT_SOURCE_DIR}
"common/protobuf/*.proto"
)
foreach(PROTO_FILE IN LISTS proto_files)
#message(STATUS "protoc proto(cc): ${PROTO_FILE}")
get_filename_component(PROTO_DIR ${PROTO_FILE} DIRECTORY)
get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE)
set(PROTO_HDR ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.h)
set(PROTO_SRC ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.cc)
#message(STATUS "protoc hdr: ${PROTO_HDR}")
#message(STATUS "protoc src: ${PROTO_SRC}")
add_custom_command(
OUTPUT ${PROTO_SRC} ${PROTO_HDR}
COMMAND protobuf::protoc
"--proto_path=${PROJECT_SOURCE_DIR}"
${PROTO_DIRS}
"--cpp_out=${PROJECT_BINARY_DIR}"
${PROTO_FILE}
DEPENDS ${PROTO_FILE} protobuf::protoc
COMMENT "Generate C++ protocol buffer for ${PROTO_FILE}"
VERBATIM)
list(APPEND PROTO_HDRS ${PROTO_HDR})
list(APPEND PROTO_SRCS ${PROTO_SRC})
endforeach()
ref: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/cpp.cmake#L234-L279
After you can use PROTO_HDR and PROTO_SRC e.g. add them to your target sources etc...
note: for .Net you can take a look at
https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dotnet.cmake#L30-L60
All in all, just adapt to your need, e.g. generate in source tree than binary dir etc. and you should be able to do whatever you want...

cmake include directories issue with cygwin

I want to add include directories to my project, which are defined in some environment variable SOME_DIR. SOME_DIR is set to 'D:\some_dir'.
Here's how I've added it in CMakeLists.txt:
include_directories($ENV{SOME_DIR}/include)
After generating Unix Makefiles via cygwin, compiler can't find header files from this directory. So, I've added some debug outputs to check list of included directories like this:
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "dir='${dir}'")
endforeach()
Output is:
dir='/cygdrive/d/myproject/D:/some_dir/include'
My question is: What should I do so that cmake include correct path, i.e. 'D:/some_dir/include'?

Create CMake/CPack <Library>Config.cmake for shared library

I have the simplest possible c-library which builds and is packed using the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project (libfoo C)
add_library(foo SHARED impl.c)
target_link_libraries(foo)
install(TARGETS foo LIBRARY DESTINATION lib/)
install(FILES public_header.h DESTINATION include/libfoo)
set(CPACK_GENERATOR "TGZ")
include(CPack)
Working example is located here: https://github.com/bjarkef/cmake-simple/tree/master/libfoo
I execute mkdir -p build; (cd build/; cmake ../; make all package;) to build a .tar.gz package with the compiled shared library along with its public header file. This is all working fine.
Now I wish to modify the CMakeLists.txt to create the FooConfig.cmake and FooConfigVersion.cmake files needed for CMake find_package in a different project to find the foo library. How do I do this?
I have discovered I should used the CMakePackageConfigHelpers: configure_package_config_file and write_basic_package_version_file, and I should create a FooLibraryConfig.cmake.in file. However I cannot figure out how to put it all together.
Note that it is important the the resulting .cmake files only contains relative paths.
I have cmake module included in the top level CmakeList.txt:
# Generate and install package config files
include(PackageConfigInstall)
Within the generic PackageConfigInstall.cmake file, the config files are created from the cmake.in files, and installed. This module can be reused for other packages.
include(CMakePackageConfigHelpers)
# Generate package config cmake files
set(${PACKAGE_NAME}_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}${PACKAGE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
configure_package_config_file(${PACKAGE_NAME}-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}/${PACKAGE_NAME}
PATH_VARS LIB_INSTALL_DIR INCLUDE_INSTALL_DIR APP_INCLUDE_INSTALL_DIR )
configure_file(${PACKAGE_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake #ONLY)
# Install package config cmake files
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake
DESTINATION
${CMAKE_INSTALL_DIR}/${PACKAGE_NAME}
COMPONENT
devel
)
You'll need a package file for your library, such as your_lib-config.cmake.in, which will become your_lib-config.cmake. This will contain the include and library variables that can be used.
get_filename_component(YOUR_LIB_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# flag required by CMakePackageConfigHelpers
#PACKAGE_INIT#
set_and_check(YOUR_LIB_INCLUDE_DIR #PACKAGE_YOUR_LIB_INCLUDE_INSTALL_DIR#/hal)
set_and_check(YOUR_LIB_LIBRARY #PACKAGE_LIB_INSTALL_DIR#/#CMAKE_STATIC_LIBRARY_PREFIX##PROJECT_NAME_LIB##CMAKE_STATIC_LIBRARY_SUFFIX#)
set_and_check(YOUR_LIB_LIBRARIES #PACKAGE_LIB_INSTALL_DIR#/#CMAKE_STATIC_LIBRARY_PREFIX##PROJECT_NAME_LIB##CMAKE_STATIC_LIBRARY_SUFFIX#)
You'll also want a config-version.cmake.in file like this:
set(PACKAGE_VERSION #PACKAGE_VERSION#)
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
There's quite a bit to the packaging scripts to get it all to work just right. I went through a lot of trial and error to finally get something that works on different targets (both linux server and embedded target). I might have left something out, so please just comment and I'll update answer.

How do I make build rules in cmake to preprocess lazy C++ .lzz files that generate .h and .cpp files?

What I'd like to do is write just Lazy C++ .lzz files and then have lzz run before a build to generate .cpp and .h files that will be built into the final application, sort of like how moc works with Qt.
Is there any way to do this?
Here is an example of how to do this... First you need to find the lzz program, for that use the find_program command:
find_program(LZZ_COMMAND lzz)
This sets LZZ_COMMAND to the path of the compiler. Then use a CMake custom command to compile the LZZ file to their C++ header/implementation files:
add_custom_command(
OUTPUT ${output}
COMMAND ${LZZ_COMMAND} -o ${CMAKE_CURRENT_BINARY_DIR} ${filename})
That generates the files in the current build directory, in case you do out-of-source builds. You will also need to specify that the outputs are generated files:
set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
Put that all together and you get a CMakeLists.txt file something like this:
cmake_minimum_required(VERSION 2.8)
project(lazy_test)
find_program(LZZ_COMMAND lzz)
function(lazy_compile filename)
get_filename_component(base ${filename} NAME_WE)
set(base_abs ${CMAKE_CURRENT_BINARY_DIR}/${base})
set(output ${base_abs}.cpp ${base_abs}.h)
add_custom_command(
OUTPUT ${output}
COMMAND ${LZZ_COMMAND} -o ${CMAKE_CURRENT_BINARY_DIR} ${filename})
set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
endfunction()
lazy_compile(${CMAKE_CURRENT_SOURCE_DIR}/example.lzz)
add_executable(test example.cpp example.h)
You would probably also want to add include path and other options to lzz eventually. If you placed all the Lazy C++ stuff into a module file and included that from the CMakeLists.txt it would be a bit cleaner. But this is the basic idea.
I just wanted to share my CMakeLists.txt, which builds upon richq's script. The *.cpp and *.hpp files now properly depend on the *.lzz files. The *.lzz files are added to the project (which answers absense's question above) but kept separate from the generated files using the source_group command.
The only remaining dealbreaker for me is the inability to compile the current file for *.lzz files.
cmake_minimum_required(VERSION 2.8)
PROJECT(LzzTest)
find_program(LZZ_COMMAND lzz.exe)
# Syntax:
# add_lzz_file(<output> <lzz file>)
# Adds a build rule for the specified lzz file. The absolute paths of the generated
# files are added to the <output> list. The files are generated in the binary dir.
#
# TODO: Support for generating template files etc.
function(add_lzz_file output filename)
# Only process *.lzz files
get_filename_component(ext ${filename} EXT)
if(NOT ext STREQUAL ".lzz")
return()
endif()
set(header_extension "hpp")
get_filename_component(base ${filename} NAME_WE)
set(base_abs ${CMAKE_CURRENT_BINARY_DIR}/${base})
set(outfiles ${base_abs}.cpp ${base_abs}.${header_extension})
set(${output} ${${output}} ${outfiles} PARENT_SCOPE)
#message("outfiles=${outfiles}, DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}")
add_custom_command(
OUTPUT ${outfiles}
COMMAND ${LZZ_COMMAND}
-o ${CMAKE_CURRENT_BINARY_DIR} # output dir
-hx ${header_extension}
-sl -hl -il -tl -nl -x # insert #line commands w/ absolute paths
-sd -hd -id -td -nd # don't output files that didn't change
${CMAKE_CURRENT_SOURCE_DIR}/${filename}
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${filename}"
)
set_source_files_properties(${outfiles} PROPERTIES GENERATED TRUE)
endfunction()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(SOURCES
A.lzz
B.lzz
main.cpp
)
foreach(file ${SOURCES})
add_lzz_file(GENERATED_SOURCES ${file})
endforeach()
source_group("" FILES ${SOURCES})
source_group(generated FILES ${GENERATED_SOURCES})
add_executable(LzzTest ${SOURCES} ${GENERATED_SOURCES})
For make:
sourcecode.h sourcecode.cpp: sourcecode.lzz
<TAB>lazy-cpp sourcecode.lzz
fill in sourcecode.h, sourcecode.cpp, and lazy-cpp with the correct values. I don't know them.