configure_file list of files -> #includes cmake - c++

This seems like something that should be easy to do, but I cant for the life of me figure out how to do it.
Basically, I want to take a source lists (for now, just a variable ${HDR_LIST}), and write them ALL as includes in a file. so if HDR_LIST="foo.h;bar.h;baz.h;quz.h" it would make the file
#include "foo.h"
#include "bar.h"
#include "baz.h"
#include "quz.h"
I'd like this file to only update if HDR_LIST changes.
The only way I can think to do it is to make a configure_file command...but this macro may be in a ton of places. Each each project sets the variable, I'm not sure how safe that is. I feel like there should be a better way...

cmake_minimum_required(VERSION 2.8)
project(MyTest)
set(CMAKE_CONFIGURABLE_FILE_CONTENT
"#include \"inc1.h\"")
set(CMAKE_CONFIGURABLE_FILE_CONTENT
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n#include \"inc2.h\"")
set(CMAKE_CONFIGURABLE_FILE_CONTENT
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n#include \"inc3.h\"")
set(CMAKE_CONFIGURABLE_FILE_CONTENT
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n#include \"inc4.h\"")
configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${CMAKE_CURRENT_BINARY_DIR}/myfile.h"
#ONLY
)
unset(CMAKE_CONFIGURABLE_FILE_CONTENT)
configure_file has a built-in write-only-if-different.

I think you are looking for some combination of foreach() and file(APPEND ...):
file(REMOVE "includes.h")
foreach(filename ${HDR_LIST})
file(APPEND "includes.h" "#include \"${filename}\"")
endforeach(filename)
Whenever HDR_LIST is changed, CMake will be run again and the file will be regenerated.
If you want to write the file only if different, it is a bit hard, because AFAIK, there are not dependencies on variables in CMake. But you could do e.g. this workaround with some hashing:
set(new_includes "")
foreach(filename ${HDR_LIST})
set(new_includes "${new_includes}#include \"${filename}\"")
if(WIN32)
set(new_includes "${new_includes}\r\n")
else()
set(new_includes "${new_includes}\n")
endif()
endforeach()
string(SHA256 new_includes_hash "${new_includes}")
file(SHA256 "includes.h" current_includes_hash)
if(NOT current_includes_hash STREQUAL new_includes_hash)
file(WRITE "includes.h" "${new_includes}")
endif()

Related

Removing path traversal of includes on CMake and QT

I am trying to setup some include paths using CMake and QT Creator and I'd like to get the rid of the path traversal on my includes. What I meant by that is below.
#include <QtTest>
#include <QCoreApplication>
#include <QDebug>
#include "../../../../UI/Controller/PageNavigator/PageNavigatorPT.h" //this works
//#include "PageNavigatorPT.h" // but this what I want
I want what is commented out, so I avoid these huge path traversals on my source. I added this to my cmake to try to fix the issue:
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(pageNavigatorTest
../../../../UI/Controller/PageNavigator/PageNavigatorBase.cpp
../../../../UI/Controller/PageNavigator/PageNavigatorPT.cpp
tst_pagenavigatortest.cpp)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}../../../../UI/Controller/PageNavigator
)
add_test(NAME pageNavigatorTest COMMAND pageNavigatorTest)
but it does not work. I still have to spell out the full path traversal.
Is there a way to make CMake make my source find the correct header by just writing:
#include "PageNavigatorPT.h" // but this what I want
thanks #Tsyvarev, this solved the problem (slash in front of the first dir
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../../../UI/Controller/PageNavigator
)

How do I include stb_image.h into my C++ project with Cmake?

I'm trying to make a project that uses the stb_image.h library that is currently sitting in my /home/user/libs/stb folder.
My CMakeLists.txt file looks like the following:
cmake_minimum_required(VERSION 3.16)
project(project_name)
set(CMAKE_CXX_STANDARD 17)
find_library(STB_LIB stb_image.h PATHS "/home/user/libs/stb/stb_image.h")
message("${STB_LIB}")
add_executable(project_name src/main.cpp)
The message I get is just STB_LIB-NOTFOUND, but I'm not sure what I would do if it did find the library. I would imagine I would want to do something regarding a target, but I could really appreciate some guidance here. I've looked around similar questions but I haven't seen one as simple as just letting me do:
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
in my main.cpp file.

C++ Constructor undefined

I work on C++ project, i use CMake to build my file. My build fail cause
undefined reference to `Software::Software()'
, but I do not see the problem. If you have an idea, do not hesitate, thank you
Files architecture:
CMake :
# cmake_minimum_required(VERSION <specify CMake version here>)
project(untitled)
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_CXX_STANDARD 11)
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_executable(untitled ${SOURCES})
Software.h :
#include <string>
class Software{
private :
std::string name;
public :
Software();
}
Software.cpp :
#include "Software.h"
Software::Software() {
this->name = "defaultName";
}
SoftwaresConfigurations.h (who call the contructor of Software) :
#include "Software.h"
class SoftwaresConfigurations {
public:
SoftwaresConfigurations();
}
SoftwaresConfiguration.cpp :
#include "SoftwaresConfigurations.h"
SoftwaresConfigurations::SoftwaresConfigurations(){
Software software = Software();
}
You have fallen into the trap that is FILE(GLOB ...).
Re-running CMake should fix this, but you should probably move away from using GLOB to collect your source files. For example, you can list them explicitly as follows:
set(SOURCES src/main.cpp src/Softwares.cpp src/SoftwaresConfigurations.cpp)
I will explain what happened below.
The official documentation says the following:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.
So what probably happened is that you created the project with just one source file. CMake ran the GLOB at configuration-time and found only the one .cpp file.
Then, you added two files (which CMake did not know about) and added the #include to your SoftwaresConfiguration.cpp. This triggers a rebuild. However, since CMake does not know about Softwares.cpp, it does not build that file and the linker produces an unreferenced symbol.

CMake: Include vs add_subdirectory: Relative header file path

I have a c++ project with several subdirectories, e.g.
src/
CMakeLists.txt
main.cpp
module1/
CMakeLists.txt
code.cpp
code.h
module2/
CMakeLists.txt
code2.cpp
It seems that the two ways to deal with this in cmake is to either use add_subdirectory(module1) or include(module1) in my src/CMakeLists.txt. Somewhere I read, that the include use is regarded legacy/deprecated. My src/module1/CMakeLists.txt looks like this:
include_directories(${CMAKE_CURRENT_LIST_DIR})
set( SRCS
${SRCS}
${CMAKE_CURRENT_LIST_DIR}/code.cpp
)
set( QT_FILE_HEADERS
${QT_FILE_HEADERS} code.h
)
If I try to use the add_subdirectory method and want to usecode.h in main.cpp I have to write #include "module1/code.h". If I do the include method of adding module1, I can simply write #include "code.h". I would prefer not to specify the relative path of the include files when I use them somewhere else, is there a way to achieve this using the add_subdirectory method? I thought the include_directories line should have taken care of that.
This is not how you should make modules -- sure you can do it this way, it works, but it is not very useful. Given your layout, simply reference module1/code.cpp in the main CMakeLists.txt file.
However, if you want to use modules, make each one a separate static library. This will really simplify things!
In src/CMakeLists.txt write:
add_subdirectory(module1)
add_executable(myprogram main.cpp)
target_link_libraries(myprogram module1)
In src/module1/CMakeLists.txt write:
add_library(module1 STATIC code.cpp)
target_include_directories(module1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
This way, you are only passing one single thing back from the module1 CMake script: the module1 target. Your main doesn't need to know anything about what happens inside there. If the code in module1 requires specific external libraries, link them there, the main CMake script won't need to know about it. Simply by linking to module1, all the magic will happen behind the scenes, your program will be compiled with the right include directories and linked to the right libraries.

CMake's equivalent to Visual Studio's Property Sheets (.vsprops)

I'm trying to migrate from Visual Studio towards Jetbrains' (awesome) CLion IDE which uses CMake to organize the projects.
Until now, the transition has been smooth: creating CMake projects and importing them into CLion is easy, and I can begin coding on one plateform then continue on another one without problems.
However, one aspect of Visual Studio that I couldn't find an equivalent to in CMake is property sheets: I use them mainly for holding the include directories' paths and the linking libs for libraries (i.e. one .vsprops file for each library, e.g. OpenCV.vsprops, Boost.vsprops, etc.).
This way, in VS, I could share a library's .vsprops file between different projects without having to configure the paths/libs each time.
Does CMake have a similar mechanism to Visual Studio's property sheets ? How is it possible to store a library's includes/libs in a CMake-parsable file then "import" it in CMakeLists.txt in order to link against the library ?
Basically, what I want to do is:
Create a "cmake property sheet" (for lack of a better name) for a given library.
Then, in CMakeLists.txt, write something like link_target_to_libs(myTarget "path/to/propertySheet1" "path/to/propertySheet2" ...) .
In CMake, libraries can export a package with IMPORTED targets which other buildsystems import using find_package:
http://www.cmake.org/cmake/help/v3.1/manual/cmake-packages.7.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#imported-targets
Instead of 'linking to property sheets', you link to the IMPORTED targets.
target_link_libraries(myTarget Dep1::Dep1 Dep2::Dep2)
Not all libraries create IMPORTED targets, and not all provide cmake config-file packages. In those cases (including OpenCV and Boost), CMake provides find modules:
http://www.cmake.org/cmake/help/v3.0/manual/cmake-developer.7.html#find-modules
which you use with find_package and link to the contents of variables.
Since I really want to make the libraries' inclusion/linking into a one-line command, and as far as my (basic) knowledge of CMake goes, I think that some compromise should be made -- mainly sharing the target name's variable between CMakeLists.txt and the "property sheets". So this is my solution... until someone proposes a simpler/cleaner one:
A CMake property sheet is a .cmake text file,
A well-known variable name --TARGET-- designates the target (i.e. the first argument of add_executable()),
Aside from library-specific commands, a .cmake file contains a call to target_include_directories(${TARGET} PRIVATE ${PATH_TO_INCLUDE_DIR}) and target_link_libraries(${TARGET} ${LIST_OF_LIBS}),
In order to use/link against a library, call include("path/to/.cmake") in CMakeLists.txt.
I have successfully built and executed a simple program that uses X11 and OpenCV with the following files:
x11.cmake
target_include_directories(${TARGET} PRIVATE "/usr/include/X11")
target_link_libraries(${TARGET} "/usr/lib/x86_64-linux-gnu/libX11.so")
opencv.cmake
# OpenCV-specific stuff
set(OpenCV_DIR "/PATH/TO/OPENCV/INSTALL/DIR/share/OpenCV") # path to OpenCVConfig.cmake
find_package(OpenCV REQUIRED)
# include path
target_include_directories(${TARGET} PRIVATE ${OpenCV_INCLUDE_DIRS})
# linking libs
target_link_libraries(${TARGET} opencv_world opencv_ts)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.4)
project(hello_clion)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
## hello-clion ##############################
# make a new target name
set(TARGET hello-clion)
# find sources
file(GLOB_RECURSE SOURCE_FILES "src/*.cpp" "src/*.hpp")
# declare a target
add_executable(${TARGET} ${SOURCE_FILES})
# link the libraries (to the last-declared ${TARGET}, which should be the last-added executable)
include("x11.cmake")
include("opencv.cmake")
#############################################
main.cpp
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <thread>
#include <opencv2/opencv.hpp>
#include <Xlib.h>
int main_x11()
{
// adapted from: http://rosettacode.org/wiki/Window_creation/X11#Xlib
}
int main_ocv()
{
// adapted from: http://docs.opencv.org/doc/tutorials/introduction/display_image/display_image.html#source-code
}
int main()
{
using namespace std;
thread tocv(main_ocv);
thread tx11(main_x11);
tocv.join();
tx11.join();
return 0;
}
Now, each time I want to use OpenCV in a project/program, I just have to put include("opencv.cmake") in the corresponding CMakeLists.txt.
This seems to work great, but there could certainly be problems I haven't discovered. (I was worried multiple macros adding the same target_link_libraries would cause "already defined" linking errors , but at least g++ 5.1.0 handles being given the same library name multiple times without error.)
In root CMakeLists.txt, BEFORE add_subdirectory() calls or globs, include:
macro(USES_WX)
include_directories(SYSTEM /usr/local/include/wx-3.0)
include_directories(SYSTEM /usr/local/lib/wx/include/gtk3-unicode-3.0)
link_directories(/usr/local/lib)
add_definitions(-D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXGTK__ -pthread)
target_link_libraries(${TARGET} pthread wx_gtk3u_xrc-3.0 wx_gtk3u_html-3.0 wx_gtk3u_qa-3.0 wx_gtk3u_adv-3.0 wx_gtk3u_core-3.0 wx_baseu_xml-3.0 wx_baseu_net-3.0 wx_baseu-3.0)
endmacro()
(You can make the macro more fancy, like checking for if CMAKE_BUILD_TYPE is "Debug" or "Release" to link to the appropriate libraries, vary preprocessor definitions, etc. See http://www.cmake.org/cmake/help/v3.0/command/if.html)
And have your project's CMakeLists.txt be like this:
set(TARGET myProgramName)
add_executable(${TARGET} myProgramName.cpp)
USES_WX()
^^ The macro call MUST be after add_executable()
And, if you want multiple target support, modify the line in the root CMakeLists.txt section shown above to:
...
target_link_libraries(${ARGV0} pthread wx_gtk3u_xrc-3.0 ...)
...
And have your project's CMakeLists.txt be like this (less lines, but more chance for error):
add_executable(myProgramName myProgramName.cpp)
USES_WX(myProgramName)