I am attempting to use the much stricter -Weffc++ compiler flag for a project. The issue that I'm having is that the project uses a bunch of open-source libraries. These libraries in no way adhere to the stricter requirements, and I have no intention of modifying them to comply.
Is there a way to target a specific set of files with a compilation option using CMake?
Furthermore, the compilation is conditional on what is compiling the program. The program can either be compiled as an executable, or it can be compiled as a library so that it can be used by the automated unit test fixtures employed.
Is there a way to target a specific subdirectory added with the add_subdirectory CMake command, with specific compile flags?
Thank you!
If you can modify all relevant targets, I recommend using target_compile_options, target_compile_definitions and or/ target_link_options to achieve your goals. You could introduce a cmake function, if the same compiler/linker options are required for multiple targets.
target_compile_options(my_target PRIVATE -Weffc++)
If you want to target a subdirectory, you should be able to use add_compile_options/add_compile_definitions/add_link_options in a new scope using a function to restruct the scope for the settings. Note that you only need a function, if the options must not apply to every target added in the same CMakeLists.txt file after adding the subdirectory and to targets created in subdirectories added from the CMakeLists.txt file after adding the subdirectory. Using a function anyways doesn't "hurt" though and may even reduce the number of things you need to consider for future edits.
function(add_subdir_with_flags DIR)
add_compile_options(-Weffc++)
add_subdirectory(${DIR} ${ARGN}) # ARGN used to allow specifying the build dir for the subdir
endfunction()
...
add_subdir_with_flags(subdir1)
add_subdir_with_flags(subdir2 builddir2)
Note: If you want to go down to the source file level, you could do so by adding compile options on a per-file basis, but you should only use this option, if not all source files of a target should be compiled with these options.
# apply options only to foo.cpp and bar.cpp
set_source_files_properties(foo.cpp bar.cpp PROPERTIES COMPILE_OPTIONS -Weffc++)
Related
I've added zlib to a CMake project like so:
project(zlib)
include(ExternalProject)
# set some variables
ExternalProject_Add(zlib_proj # boring stuff omitted ...
)
add_library(zlib SHARED IMPORTED GLOBAL)
add_dependencies(zlib zlib_proj)
set_target_properties(zlib PROPERTIES
# ...
INTERFACE_INCLUDE_DIRECTORIES "${INCLUDE_DIR}"
)
I've chosen to build zlib within my CMake project instead of using the system zlib.so in order to guarantee that the same zlib is used regardless of where the project is cloned and built (this choice is not up for debate).
Elsewhere, another target links zlib through target_link_libraries. In a source file in that dependent target, I #include <zlib.h>. It compiles fine, and I am fairly certain that zlib.so is built and linked correctly as well. However, <zlib.h> is available from the system as well. I could probably manually verify that I am including the <zlib.h> in ${INCLUDE_DIR} by adding a bogus variable and using it in a dependent source file, but I really would like to automatically assert that the correct file is included during any compilation on any machine. Determining that the included zlib.h lives somewhere in the CMake build directory is probably sufficient.
I believe CheckIncludeFileCXX doesn't quite solve the problem; I need to verify which zlib.h is actually included in a specific source file. Knowing that my locally provided zlib.h can be included at all is certainly a prerequisite, but it doesn't fully answer my question.
You could achieve that by making the compiler generate the dependency files for the needed .cpp file and then adding a custom build step that verifies the path of zlib.h by grep or any other means. So, in short (since I am not a CMake expert):
Add -MD -MF to C/C++ flags (or maybe CMake has some nice way to enable dependency generation or maybe even does it by default - not really sure).
Add a add_custom_command (or again maybe there is something nicer) to verify the path of <zlib.h> in the generated dependency file.
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.
I have a C++ program that I'm building with Clang 3.9's profile-guided optimization feature. Here's what's supposed to happen:
I build the program with instrumentation enabled.
I run that program, creating a file with profile-data: prof.raw.
I use llvm-profdata to convert prof.raw to a new file, prof.data.
I create a new build of that same program, with a few changes:
When compiling each .cpp file to a .o file, I use the compiler flag -fprofile-use=prof.data.
When linking the executable, I also specify -fprofile-use.
I have a Gnu Makefile for this, and it works great. My problem arises now that I'm trying to port that Makefile to CMake (3.7, but I could upgrade ). I need the solution to work with (at least) the Unix Makefiles generator, but ideally it would work for all generators.
In CMake, I've defined two executable targets: foo-gen and foo-use:
When foo-gen is executed, it creates the prof.raw file.
I use add_custom_command to create a rule to create prof.data from prof.raw.
My problem is that I can't figure out how to tell CMake that each of the object files depended upon by foo-use has a dependency on the file prof.data.
The most-promising idea I had was to (1) find a way to enumerate all of the .o files upon which foo-use depenends, and then (2) iterate over each of those .o files, calling add_dependency for each one.
The problem with this approach is I can't find an idiomatic way, in my CMakeLists.txt file, to enumerate the list of object files upon which an executable depends. This might be an open problem with CMake.
I also considered using set_source_files_properties to set the OBJECT_DEPENDS property on each of my .cpp files used by foo-use, adding prof.data to that property's list.
The problem with this (AFAICT) is that each of my .cpp files is used to create two different .o files: one for foo-gen and one for foo-use. I want the .o files that get linked into foo-use to have this compile-time dependency on prof.data; but the .o files that get linked into foo-gen must not have a compile-time dependency on prof.data.
And AFAIK, set_source_files_properties doesn't let me set the OBJECT_DEPENDS property to have one of two values, contingent on whether foo-gen or foo-use is the current target of interest.
Any suggestions for a clean(ish) way to make this work?
Discussion on author's idea #1
The most-promising idea I had was to (1) find a way to enumerate all of the .o files upon which foo-use depenends, and then (2) iterate over each of those .o files, calling add_dependency for each one.
This shouldn't work according to the documentation for add_dependencies, which states:
Makes a top-level depend on other top-level targets to ensure that they build before does.
Ie. You can't use it to make a target depend on files- only on other targets.
Discussion on author's idea #2
I also considered using set_source_files_properties to set the OBJECT_DEPENDS property on each of my .cpp files used by foo-use, adding prof.data to that property's list.
The problem with this (AFAICT) is that each of my .cpp files is used to create two different .o files: one for foo-gen and one for foo-use. I want the .o files that get linked into foo-use to have this compile-time dependency on prof.data; but the .o files that get linked into foo-gen must not have a compile-time dependency on prof.data.
And AFAIK, set_source_files_properties doesn't let me set the OBJECT_DEPENDS property to have one of two values, contingent on whether foo-gen or foo-use is the current target of interest.
In the comment section, you mentioned that you could solve this if OBJECT_DEPENDS supported generator expressions, but it doesn't. As a side note, there is an issue ticket tracking this on the CMake gitlab repo. You can go give it a thumbs up and describe your use-case for their reference.
In the comments section you also mentioned a possible solution to this:
Potential other solution a) double project system where main user invoked project forwards settings to second pgo project compiling same settings again.
You can actually put this into the CMake project via ExternalProject so that it becomes part of the generated buildsystem: Make the top-level project include itself as an external project. The external project can be passed a cache variable to configure it to be the -gen version, and the top-level can be the -use version.
Speaking from experience, this is a whole other rabbit hole of long CMake-documentation-reading and finicking sessions if you have never manually invoked or done anything with ExternalProject before, so that answer might belong with a new question dedicated to it.
This can solve the problem of not having generator expressions in OBJECT_DEPENDS, but if you want to have multi-config for the top-level project and that some of the configs in the multi-config config not be for PGO, then you will be back to square one.
Proposed Solution
Here's what I've found works to make sources re-compile when profile data changes:
To the custom command which runs the training executable and produces and re-formats the training data, add another COMMAND which produces a c++ header file containing a timestamp in a comment.
Include that header in all sources which you want to re-compile if the training has been re-run.
If you want to support non-PGO builds, wrap the timestamp header in a header which checks that it exists with __has_include and only includes it if it exists.
I'm pretty sure with this approach, CMake doesn't do the dependency checking of TUs on the profile data, and instead, it's the generated buildsystem's header-dependency tracking which does that work. The rationale for including a timestamp comment in the header file instead of just "touch"ing it to change the timestamp in the filesystem is that the generated buildsystem might detect changes by file contents instead of by the filesystem timestamp.
All the shortcomings of the proposed solution
The painfully obvious weakness of this approach is that you need to add a header include to all the .cpp files that you want to check for re-compilation. There are several problems that can spawn from this (from least to most egregious):
You might not like it from an aesthetics standpoint.
It certainly opens up a hole for human-error in forgetting to include the header for new .cpp files. I don't know how to solve that.
You might not be able to change some of the sources that you need to re-compile, such as sources from third-party static libraries that your library depends on. There may be workarounds if you're using ExternalProject by doing something with the patch step, but I don't know.
Unfortunately I don't know how to solve any of those problems. For my personal project, #1 and #2 are acceptable, and #3 happens to not be an issue.
My project is quite simple but I like to keep files in different folders for clarity. For instance I have three folders.
An Output folder that contains all the classes used for the output. (for now only Output.cc and Output.h).
A Math folder, containing all of the classes related to math. (vector.cc, vector.h, randomgen.h, randomgen.cc, etc)
A Tests folder where there are different cpp files each containing a main function. (Output_test.cc, vector_test.cc, etc)
How can I create a CMake script that complies all of the different main function of the different test programs using the classes that are in different folders?
In addition, I didn't see where the compiler, and its options, are specified in a CMake file.
How to specify the compiler?
There are a few ways to specify the compiler you want to use. Settings environment variables, defining compiler variables, or designating a generator.
Settings Environment Variables
There are two ways to use environment variables to help CMake determine which compiler to use during a CMake configuration. Using the PATH variable or the CC and CXX variables.
PATH
Make sure the path to your desired compiler is first in the list. If you don't want to modify your path, then use the 2nd option.
CC & CXX
CMake reads the variables CC and CXX to determine the path for the C compiler and C++ compiler respectively. Note that the first time CMake is configured for a project it will cache these paths, and look to the cache first for all future configurations. So if you wish to change the compiler path, be sure to delete the cache file CMakeCache.txt. As HughB pointed out, there is a good example of this given by Guillaume
Defining Compiler Variables
Similar to using CC and CXX, there are CMake variables that can be defined at the commandline to choose the desired compiler. They are CMAKE_C_COMPILER and CMAKE_CXX_COMPILER. You can set them using the -D option and they use the same values as CC and CXX. Note, just like CC and CXX these are cached after the first CMake configuration.
Example
cmake -DCMAKE_CXX_COMPILER=/usr/bin/g++4.6/g++ -DCMAKE_C_COMPILER=/usr/bin/gcc4.6/gcc <path to src>
Designating a Generator
The last way to choose the compiler is by using the -G option to select a generator. There are numerous generators to choose and I recently answered a question about them. I'm not going to go into too much detail about them in this answer, but you can read my other answer for more details.
Example
cmake -G "Unix Makefile" <path to src>
Don't Hardcode the Compiler
I recommend resisting the urge to "hardcode" the compiler in the CMakeLists.txt files. CMake is meant to be compiler independent and you should be setting the compiler information external of the CMake files. Use one of the methods mentioned above to keep your CMake files portable and to avoid confusion if yourself or someone else wants to build the project with a different compiler.
Related references. (Disclaimer: Written by me)
What is a CMake generator
Understanding the Purpose Behind CMake
How to Compile Multiple Executables?
As HughB mentioned use add_executables. You could also create separate libraries for each folder group, there are many ways to organize your project. I'm going to keep it simple and give an example that builds two executables in the same project.
For this example I created 5 files:
include/Helloworld.h
#include <stdio.h>
src/HelloWorld.cpp
#include "HelloWorld.h"
int main()
{
printf("Hello World!\n");
return 0;
}
include/HelloWorld2.h
#include <stdio.h>
src/HelloWorld2.cpp
#include "HelloWorld2.h"
int main()
{
printf("Hello World2!\n");
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
# This is required to compile and must contain the paths to
# all of the header files
include_directories(include)
# These are optional, but are added to be passed to the
# add_executable command so that the headers are accessible
# from within the project
set(HW_INCLUDES include/HelloWorld.h)
set(HW_INCLUDES2 include/HelloWorld2.h)
project(HelloWorlds)
# Required sources
set(HW_SOURCES src/HelloWorld.cpp)
set(HW_SOURCES2 src/HelloWorld2.cpp)
add_executable(HelloWorld ${HW_SOURCES} ${HW_INCLUDES})
add_executable(HelloWorld2 ${HW_SOURCES2} ${HW_INCLUDES2})
When this project is built there will be two executables: HelloWorld.exe and HelloWorld2.exe.
Consider putting the code that will be used in different program mains in a library. Use the add_library command to do make a library. You could have a directory hierarchy like this:
TopDir
CMakeLists.txt
MyLib
CMakeLists.txt
vector.cc
vector.h
....
MyExe1
CMakeLists.txt
main1.cc
MyExe2
CMakeLists.txt
main2.cc
Use add_subdirectory in your top level cmakelists.txt to traverse the directories. In the dirs that build executables, use add_executable and target_link_libraries. If you named the library MyLib then your target_link_libraries command would look like
target_link_libraries( exe1 MyLib )
In regard to overriding the compiler, see how to specify new gcc path for cmake
Say I'm working on a library, foo. Within my libraries source files, I'd like to include headers the same way a user of my library would:
#include <foo/bar.hpp>
// code defining bar methods here
In boost for example, includes of other headers within boost are done that way, e.g. <boost/shared_ptr.hpp>, rather than the relative quoted "../shared_ptr.hpp" style. I looked at how some other libraries accomplish this and it appears they add a redundant directory to their file layout in order to do it, e.g. the boost code lives in "boost_1_4_1/boost" rather than just "boost_1_4_1/".
Switching to that scheme is annoying if you already have source control using an existing layout. What's the best way with GNU make to layer it on? My only thought is to add a target that all build targets depend on that makes a hidden folder with a symlink inside to my source tree, and add that hidden folder to the include path. Perhaps there's a less obfuscated way?
Couldn't you use -I gcc key of INC option for your Makefile?
gcc:
gcc -c -I/home/joseph/dev/foo/headers
Makefile:
INC=-I/home/joseph/dev/foo/headers
In this case you would have only one place to make this change, Makefile.