Remove a source file after adding it with target_sources() in CMake - c++

I am using CMake 3.16.
I add my source files to my target with target_sources(). I would like later in my CMakeLists.txt to remove a source file I previously added with target_sources().
For example:
target_sources(my_target PRIVATE main.c abc.c def.c ghi.c)
# Later...
# Remove def.c from the previously added source files.
Is there a way to do this ideally without setting a custom "sources" variable and removing it from this list with list(REMOVE_ITEM ...)?
EDIT:
The context of this question is unit testing static functions in C.
My program is made of a lot of static functions that I want to unit test. To test them, I decided to include the .c file in the test files instead of the .h.
For example:
abc.c:
#include "abc.h"
// several static functions defined here
abc.h:
// some stuff
test_abc.c:
#include "unity.h" // a unit test framework
#include "abc.c" // notice the .c instead of the .h to be able to test the static functions
// the test functions
By doing this, I need to remove in CMake the xxx.c file if I add the test_xxx.c file because otherwise the content of the xxx.c file will be defined 2 times and the linker will not be happy with it.

You can set the source file property HEADER_FILE_ONLY to ON on the source file in question. See also set_source_files_properties().
Since CMake version 3.18, you can also do this if the source file belongs to a target defined in a different directory:
set_source_files_properties(subdir/source.c TARGET_DIRECTORY target-from-subdir PROPERTIES HEADER_FILE_ONLY ON)

Related

CMake/make apply -D flags on header files

I'm (cross-)compiling a shared C library with support for many different platforms which is handled by an hierarchy of CMakeLists files. In those files, several platform specific compiler flags are conditionally produced (with add_definitions()). I can successfully compile and link the source code leading to an appropriate .so file.
But to use the library in any project, I need to provide the right header files, too. The following install command of CMake selects the right header files to copy but does not apply the replacement of preprocessor defines/includes:
install(FILES ${headers} DESTINATION include/mylibrary)
So how can I generate/install the "post-compiled" header files?
What I thought of so far:
As add_definitions() should stack my -D's in the COMPILE_DEFINITIONS variable, maybe running a foreach loop on the copied raw headers and replace the define/include placeholders?
Using add_custom_command() to apply some logic before copying?
Edit: As pointed out by Tsyvarev, there is an answer quite near to my needs here, but unfortunately not quite it. In summary, the answer gives 2 options:
Include a special 'config' header in all of the library's headers and leverage the cmakedefine command to call configure_file() on this header. I can't use this approach because I don't want to alter the library headers.
Create a target-specific .cmake file which helps external projects in including the right headers together with all necessary -D defines. I can't use this approach either, because my external projects do not use cmake for building. Plus, I wish to create a library that is as easy to include as possible.
Any other thoughts?
Edit 2: I may have to elaborate on my statement, that the install command of CMake is not replacing defines. Take the following example:
//sampleheader.hpp
#ifndef SAMPLEHEADER_HPP_
#define SAMPLEHEADER_HPP_
#include OS_SPECIFIC_HEADER
//...
Now I have a CMakeLists.txt file that does something like this:
# ...
if (${OS} MATCHES "arm-emblinux")
add_definitions(-DOS_SPECIFIC_HEADER="emblinuxHeader.hpp")
elseif (${OS} MATCHES "linux")
add_definitions(-DOS_SPECIFIC_HEADER="linuxHeader.hpp")
endif()
# ...
Everything compiles fine, but when the install command above gets called, I have a header file in my ../include/ directory still with OS_SPECIFIC_HEADER placeholder in it. And of course, this cannot be properly included in any development project.

Is it possible to replace certain symbol to different symbol with CMake?

I'm trying to make an executable with CMake.
This executable requires full path to file which is located in the project.
int main()
{
std::ifstream("fullpath_to_file");
//....
}
I think if CMake can replace certain symbols in source code with user specified string, there will be no need of hard-coding fullpath.
For example, if CMake can replace ${CMAKE_PROJECT_DIR} in source code(cpp) into a cmake's variable like ${PROJECT_SOURCE_DIR}, then I would be able to write source like this.
int main()
{
std::ifstream("${CMAKE_PROJECT_DIR}/input/my_input.txt");
//....
}
Is there any way to do this?
Thanks.
A good way to expose as many CMake variables to you source files as you want is creating a configuration header to your project. First, create a template to the header, call it say config.h.in and define the symbols you want CMake to set at build time, for exemple the contents of config.h.in your case can be
#ifndef __CONFIG_H__
#define __CONFIG_H__
#define PROJECT_DIR #CMAKE_PROJECT_DIR#
#endif
then add to your CMakeLists.txt an instruction to change this configuration header and replace the value between the #'s with the value of the corresponding cmake variable. For instance, put the following in CMakeLists.txt:
include_directories(${CMAKE_BINARY_DIR})
config_file(
${CMAKE_SOURCE_DIR}/config.h.in
${CMAKE_BINARY_DIR}/config.h
)
Then CMake will create config.h with the definitions for the values you want to acces from your sources. Now all you have to do is: include config.h in your c++ sources and use the PROJECT_DIR macro as you expect.
No, CMake cannot do this directly. And you shouldn't do it, because you would have to place your source code within your build directory instead of your source directory.
The usual way - with respect to C++ and CMake - is to use a macro FOO_PATH in your C++ code and
pass -DFOO_PATH=<path_to_foo> via CMake.
add a define #cmakedefine FOO_PATH FOO_PATH to your configure file config.h, define FOO_PATH within your CMake code, and regenerate your config.
How do you do this when using ctest. In this instance there is no .h file to include, but needs to modify .cc files that are compiled? Such that it does not modify the original ${CMAKE_SOURCE_DIR} files
add_compile_definitions(TEST_DATA_DIR="${CMAKE_SOURCE_DIR}/data")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test_file.cc
${CMAKE_CURRENT_BINARY_DIR}/test_file.cc)
and in C++:
std::string filename = "TEST_DATA_DIR/data.txt";
std::cout << filename << std::endl;
...
outputs "TEST_DATA_DIR/data.txt"

Adding header and .cpp files in a project built with cmake

I have built a project using cmake and some libraries.I want however to add some header and .cpp files in the project which I am going to code.What is the easiest way to do it?Can I just create a .cpp and header files and then build again project in Visual Studio? Or due to the fact that project was built using cmake I can't?
You can put all header/source files in the same folder and use something like
file(GLOB SOURCES
header-folder/*.h
source-folder/*.cpp
)
add_executable(yourProj ${SOURCES})
In this way, you can do either of the following two methods to add new added header/source into VS:
need to generate in CMake again.
fake to edit the CMakeLists.txt a little bit, e.g. simply add a space. And then build your solution in VS, it will automatically add new header/source files.
you need to add every .h and .cpp file to CMakeList.txt like this:
# Local header files here ONLY
SET(TARGET_H
Header.h
Plugin.h
messagelog.h
win32application.h
timer.h
)
# Local source files here
SET(TARGET_SRC
Plugin.cpp
messagelog.cpp
win32application.cpp
timer.cpp
)
then configure and build the solution again and reload it in VS.
Although it's a late Response and I just saw it. I am using CLion IDE from JetBrains, which adds these header and .cpp files automatically when you create them. Although it may not be your need, it may be useful for other peoples who see it.

Using cmake's automoc on external header files without knowing their filenames

In essence I want to be able to moc header files that are not part of any target in cmake with the additional difficulty that I don't know the filenames of those headers.
The actual project is quite complex and part of an automated build system. The following is an easy example.
Consider a project structured like this:
CMakeLists.txt
src/lib/source.cpp
src/lib/CMakeLists.txt
src/include/some_header.hpp # which is included in source.cpp
Content of main CMakeLists.txt:
cmake_mimimum_required(VERSION 2.8.6)
project("automoctest")
add_subdirectory(src/lib)
Content of src/lib/CMakeLists.txt:
include_directories(${CMAKE_HOME_DIRECTORY}/src/include)
find_package(Qt4 4.8 REQUIRED QtCore)
include(UseQt4)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(foo SHARED source.cpp)
target_link_libraries(foo ${QT_LIBRARIES})
set_target_properties(foo PROPERTIES AUTOMOC true)
Inside source.cpp the file some_header.hpp is included like this:
#include "some_header.hpp"
The Problem:
The file some_header.hpp includes a Q_OBJECT and has some signals, so moc needs to work its magic. But as the header is not inside the actual project the header will not get mocked. I don't even know the filename of some_header.hpp so I can't add it specifically to be mocked. Obviously AUTOMOC does not check the include_directories for mockable files even when a source file includes one of them.
What I tried (unsuccessfully):
use #include moc_some_header.cpp in source.cpp as it is described in the cmake documentation. This leads to an error in which cmake complains that it could not find some_header{.h,.hpp,.hxx,.H}
setting CMAKE_AUTOMOC_RELAXED_MODE to true. Even though it's not clear from the doc what this actually does. Made no difference anyway.
setting AUTOMOC_MOC_OPTIONS to -Isrc/include or -I/path/to/project/src/include or -I${CMAKE_HOME_DIRECTORY}/src/include Doesn't do anything that I could see.
The great thing about AUTOMOC is that I don't need to know which files actually need to be mocked. In this case however I would need to know all the headers that might have a Q_OBJECT inside, that are included by my source files.
Is there a way to tell AUTOMOC where exactly to look for mockable files?
Did you truly set AUTOMOC_MOC_OPTIONS to -Isrc/include, or to -I/path/to/myproject/src/include? The former probably doesn't exist.
I have always used the MOC macros; it looks like AUTOMOC is something new that is built into CMake.
I usually include all headers when creating a library or executable - i.e.
add_library(foo SHARED source.cpp ../include/some_header.hpp )
I assume that this will allow AUTOMOC to work. It will have the added benefit of causing make to work as expected - rebuilding your library when the header changes.
If you are truly unable to add the file to the add_library command ahead of time, then I think you'll have to write a cmake function to search for #include statements within source.cpp, locate those files, and search them for Q_OBJECT. If they match, add them to a variable - perhaps EXTRA_MOCS. Then, the add_library line becomes
add_library(foo SHARED source.cpp ${EXTRA_MOCS} )

including header file in a separate folder

I created a class (say, myclass.h/cpp). I want to use the class from many different places. Therefore, I put those files in a folder (say, C:\cpp_include) and I want to include them from whatever folder my codes are. I have a code which uses the class (say, main.cpp). In main.cpp, I include myclass:
#include "myclass.h"
I compile using a .pro file and nmake. In the .pro file, I specify the folder as:
INCLUDEPATH += C:\cpp_include
When I compile the code using nmake, myclass.h is properly included, but myclass.cpp doesn't seem to be found by compiler.
When I specify myclass.cpp as one of the source files in .pro file:
SOURCES += main.cpp C:\cpp_include\myclass.cpp
The exe file is built correctly. But, I would like myclass.cpp file to be found automatically when myclass.h is included, i.e. without setting myclass.cpp as a source file. Would this be possible? It looks like that's what happens with classes from Qt and Qwt (e.g .h/cpp files in /src/ folder in Qt and Qwt). Am I missing somthing?
Thanks a lot!
Daisuke
A simple technique is to have build scripts (makefiles) in the cpp directories. Write a rule that traverses the directories, executing the build scripts. This one step in isolating functionality and also allows one to use libraries.
That's just not how it works. The .cpp is the file that matters, header files (.h) just get copied into the other .cpp files. Therefore you need to add the myclass.cpp to your sources for compiling. Or, if it's a library class, you could also compile it once into a static library (.lib) and just add that to your linker files. But you ultimately need to somehow include you implementation in the project where it's used.