Specify how cmake creates visual studio project - c++

I'm setting up cmake for my project and I've set up a testing project for it. When it generates my visual studio 2010 project I want to make it as the project I've had earlier.
it creates a ALL_BUILD and ZERO_CHECK project that I dont want.
it puts the .h files into the External Dependencies folder. I want a Include Files folder where all the .h files goes.
I also want to group some files under different filters. Like in my core lib I want to group all files related to Maths in a folder and all files related to Event management in another.
On the filesystem it puts the project files inside /Lib/src. Probably cause I have it organized that in the code folder, but I dont want that for the project files.
I want to set up different configuration so I have DebugOpenGL, DebugDirectX, ReleaseOpenGL, ReleaseDirectX and then setting a flag USE_OPENGL or USE_DIRECTX for the two types of configurations.
How can I exclude some files when I build on windows and others when I build on linux? Like I have WindowWin.cpp and WindowLinux.cpp.
I've tried what you sugested but cant get it working:
#LibProject/src
FILE(GLOB test0_headers $CMakeTest_SOURCE_DIR/LibProject/inc/test.h)
source_group(include0 FILES ${test0_headers})
FILE(GLOB test0_source ${CMakeTest_SOURCE_DIR}/LibProject/src/test.cpp)
source_group(source0 FILES ${test0_source})
FILE(GLOB test1_headers $CMakeTest_SOURCE_DIR/LibProject/inc/test1.h)
source_group(include1 FILES ${test1_headers})
FILE(GLOB test1_source ${CMakeTest_SOURCE_DIR}/LibProject/src/test1.cpp)
source_group(source1 FILES ${test1_source})
include_directories(${test0_headers} ${test1_headers})
add_library(LibProject ${test0_headers} ${test1_headers} ${test0_source} ${test
1_source})
I kind of got it working now.. only that I want sub folders for headers and source files inside the source group.
set(test_source0 ${CMakeTest_SOURCE_DIR}/LibProject/inc/test.h ${CMakeTest_SOURCE_DIR}/LibProject/src/test.cpp)
source_group(TEST FILES ${test_source0})
set(test_source1 ${CMakeTest_SOURCE_DIR}/LibProject/inc/test2.h ${CMakeTest_SOURCE_DIR}/LibProject/src/test2.cpp)
source_group(TEST2 FILES ${test_source1})
include_directories(${CMakeTest_SOURCE_DIR}/LibProject/inc)
add_library(LibProject ${test_source0} ${test_source1})
Heres my solution :)
set(test_header
${CMakeTest_SOURCE_DIR}/LibProject/inc/test.h)
set(test_source
${CMakeTest_SOURCE_DIR}/LibProject/src/test.cpp)
source_group(TEST\\Headers FILES ${test_header})
source_group(TEST\\Source FILES ${test_source})
set(test2_header
${CMakeTest_SOURCE_DIR}/LibProject/inc/test2.h)
set(test2_source
${CMakeTest_SOURCE_DIR}/LibProject/src/test2.cpp)
source_group(TEST2\\Headers FILES ${test2_header})
source_group(TEST2\\Source FILES ${test2_source})
include_directories(${CMakeTest_SOURCE_DIR}/LibProject/inc)
add_library(LibProject
${test_header}
${test_source}
${test2_header}
${test2_source})

To group files into a folder in Visual Studio you can use:
# Include files
FILE(GLOB all_headers "include/*.h*")
source_group("include" FILES ${all_headers})
# Source files
FILE(GLOB all_srcs "src/*.cpp")
source_group("source" FILES ${all_srcs})
This will put all of your .h files that are located in the include folder to appear in a folder called include in Visual Studio. Same for your cpp files. You can use this technique to make your own structure in CMake, if that is what you want.
For the purposes of ALL_BUILD and ZERO_CHECK read this answer. To disable the generation of ZERO_CHECK use set(CMAKE_SUPPRESS_REGENERATION true).
To select between OpenGL and DirectX and to setup the appropriate folders, you can use the same technique used above but put them inside a
if(${USE_OPENGL})
FILE(GLOB ....)
endif()
I think you get the idea.

I'll answer the ones I know:
The ALL_BUILD and ZERO_CHECK are used to keep your projects in sync with changes to the CMakeFiles. I don't think there's a way to get rid of those.
To get the .h files where you want them, you need to include them as part of the source. I use something like this:
file(GLOB LocalProjectIncludes "${yourheaderdirectory}/*.h")
Then I append ${LocalProjectIncludes} to the source files for the project. CMake will figure out that they're headers; it won't try to build them.

Related

How can I cleanly place files in the "root" filter in Visual Studio using CMake?

We're using CMake to generate our Visual Studio solutions. Our project is a "whole" app consisting of header files together with the source files (.h/.cpp).
We like to have the source/header files well nested under the filters in Visual Studio (the "folders" in the Solution Explorer), the same way we see them in the Windows File Explorer.
So we came up with something like this to achieve this:
# ...the files are added to the project in another way.
#
# Group files under filters
#
file(GLOB source_files *.cpp *.h )
file(GLOB source_files_benchmark benchmark/*.cpp benchmark/*.h )
file(GLOB source_files_builder builder/*.cpp builder/*.h )
file(GLOB source_files_demo demo/*.cpp demo/*.h )
file(GLOB source_files_dashboard dashboard/*.cpp dashboard/*.h )
file(GLOB source_files_gsl gsl/* )
file(GLOB source_files_jsonUtil2 jsonUtil2/*.cpp jsonUtil2/*.h )
source_group( "" FILES ${source_files} )
source_group( "benchmark" FILES ${source_files_benchmark} )
source_group( "builder" FILES ${source_files_builder} )
source_group( "dashboard" FILES ${source_files_dashboard} )
source_group( "demo" FILES ${source_files_demo} )
source_group( "gsl" FILES ${source_files_gsl} )
source_group( "jsonUtil2" FILES ${source_files_jsonUtil2} )
(Please note that we're using "the evil" file GLOB to generate our lists. We're aware of the risks and we found out that they were less of an inconvenience than to add new files manually; I also don't think the way we get the file list is relevant here.)
This works and we have the nice project structure when we load the project in Visual Studio.
I though I could probably improve upon this and came up with this alternative solution:
# Nicely put the files into "filters" in Visual Studio. We used to do this
# manually but this way requires less work, overall.
# Get all the files CMake knows about.
get_target_property(local_app_sources ${my_target} SOURCES)
get_target_property(local_app_headers ${my_target} HEADERS)
set(local_app_files ${local_app_sources})
list(APPEND local_app_files ${local_app_headers})
# Create two lists, one we'll use for the "root", and one we'll use for the "in
# folders". More details below.
set(local_root_files ${local_app_files})
set(local_in_folder_files ${local_app_files})
list(FILTER local_root_files EXCLUDE REGEX ".*/.*")
list(FILTER local_in_folder_files INCLUDE REGEX ".*/.*")
# For some reasons, CMake will place the files that are at the "root" under the
# "Source Files" filter in Visual Studio, so we have moved those files to their
# own list. We use the source_group(TREE command to make a nice tree with the
# files that are under a folder, and we'll use the default version of the
# command to place the files that are at the root into an "empty string" folder
# (no folder), so that they'll be placed at the root.
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${local_in_folder_files})
source_group( "" FILES ${local_root_files} )
I'm happy that we don't have to add new folders manually anymore. However, I find it's still a bit verbose and I'm wondering if I could achieve the same with a single call to source_group(TREE, without the need to split the list and put the files that are at the "root" explicit into that folder.
How can I achieve this? What am I missing?
I've tried the "PREFIX" parameter but it just put everything into that folder (I end up with <prefix>/Source Files/src..), and we also don't need a prefix.
We're using CMake 3.8.something (I know, it's old and we should upgrade... we'll get to it, someday.)
Your first solution can be simplified by using REGULAR_EXPRESSION option of source_group instead of FILES option.
This will also get rid of the evil GLOB command.
source_group("benchmark" REGULAR_EXPRESSION "benchmark/.+\.(h|cpp)")
source_group("builder" REGULAR_EXPRESSION "builder/.+\.(h|cpp)")
...
See CMake Regex Specification.
As for the TREE option, your solution is pretty good.
With the following minor modification, I can get the filtering behaviour as you desire, where files are filtered according to their folder name, and the ones at the root folder has no filter instead of being listed under "Source Files".
get_target_property(_sources my_target SOURCES)
get_target_property(_headers my_target HEADERS)
set(_files ${_sources} ${_headers})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${_files})
Note that it is sometimes necessary to run CMake command in a clean build environment for VS filters to take effect.
I suspect that was the reason you had to apply a workaround to the TREE solution.

CMake and VisualStudio: Group files in solution explorer

To finish a long coding session on a project, I wanted to test if my CPP project is compilable on an arrangement of OS'es.
I've been working in Win10 all the time. Compiles fine.
I've tried a Raspberry Pi. Compiles fine.
I re-download a seperate copy of my project to a Win10 client, run cmake-gui, and open the project: My folder structure in the solution explorer all gone.
So I started digging around, and apparently this structure is kept in CMakeLists.txt with the command source_group. So I start adding more source_groupings to my cmake lists, and for some reason my groupings won't take.
Example:
source_group("game\\entitysystem" FILES ${entitysystem_SRC}) // Existing grouping
source_group("game\\entitysystem\\components" FILES ${components_SRC}) // My new grouping
My glob would be this:
file(GLOB components_SRC
"game/components/*.h"
"game/components/*.cpp"
)
file(GLOB entitysystem_SRC
"game/entitysystem/*.h"
"game/entitysystem/*.cpp"
)
I do believe my GLOB's are correct since the new project-clone compiles fine. It's just that every part of the new structure in Visual Studio's Solution Explorer seems lost. Yes, I have cleared Cmake's cache and regenerated the project. Doesn't change it.
Original structure:
Cloned project structure:
Edit:
I did make a mistake in my source_group as in that it should not put components beneath entitysystem, but still, why aren't there any filters created in Visual Studio?
First, make sure you are setting set_property(GLOBAL PROPERTY USE_FOLDERS ON).
Second, it is not recommended to use GLOB to collect a list of source files. From the file(GLOB documentation:
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.
The recommended way to list project files is to add them by hand to CMakeLists.txt.
If you still want to GLOB, it looks like you want to mirror the directory structure in your source tree. You can use a macro such as this every place you define a library or executable to automatically sort them for you:
foreach(FILE ${SRCS})
# Get the directory of the source file
get_filename_component(PARENT_DIR "${FILE}" DIRECTORY)
# Remove common directory prefix to make the group
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}")
# Make sure we are using windows slashes
string(REPLACE "/" "\\" GROUP "${GROUP}")
# Group into "Source Files" and "Header Files"
if ("${FILE}" MATCHES ".*\\.cpp")
set(GROUP "Source Files${GROUP}")
elseif("${FILE}" MATCHES ".*\\.h")
set(GROUP "Header Files${GROUP}")
endif()
source_group("${GROUP}" FILES "${FILE}")
endforeach()

cmake: read and compile dynamically-generated list of cpp files

I have a custom tool that processes a given list of IDL files and produces a number of .cpp and .h files as output. I want to add those files to the list of things to compile in my CMakeLists, and also model the dependencies those files have on the IDL.
To keep things simple, I will state that any change to any of the IDL files should trigger a regeneration of all cpp/h.
I have a custom command that takes care of running the generator tool and listing all the IDL files as dependencies.
My issue is getting the subsequent list of cpp/h files into cmake at build-time. It is not possible to infer from the name of the IDL files what cpp files will be generated. My generator tool will, however, output the list of generated files to a text file.
So my question is: how do I instruct cmake to "read from this text file and add the contents as extra source and header files to be compiled", also bearing in mind that the said text file only exists during a certain point of the build?
CMake needs to be able to infer the names of all .cpp files participating in the build at configure time. It is not possible to add files afterwards without re-running CMake.
One possible approach would be to use a two-phase CMake build: Instead of building the generated source files directly from your main project, you create a separate CMake project for building just the generated sources.
Then in your main CMake project you add a custom target that runs after the code generation and invokes CMake to both configure and build the generated files project.
The disadvantage here is that the generated files no longer appear as part of the main project. Also some trickery is required if you don't want to rebuild the generated sources every time - custom targets are always considered out-of-date, so you might want to use a script here that only runs CMake on the subproject if the generated files changed.
This is a few years late but this works just fine:
#run whatever tool that generates the cpp files
execute_process(COMMAND "./your_tool.sh")
#read files from files.txt and make a cmake 'list' out of them
file(READ "files.txt" SOURCES)
#found this technique to build the cmake list here:
#http://public.kitware.com/pipermail/cmake/2007-May/014236.html
#maybe there is a better way...
STRING(REGEX REPLACE ";" "\\\\;" SOURCES "${SOURCES}")
STRING(REGEX REPLACE "\n" ";" SOURCES "${SOURCES}")
#at this point you have your source files inside ${SOURCES}
#build a static library...?
add_library(mylib STATIC ${SOURCES})
There is a function that build the list directly from file:
file(STRINGS <filename> <variable> [<options>...])
source: https://cmake.org/cmake/help/v3.11/command/file.html

Visual Studio 2010 project file filters

I have a complex C/C++ bunch of applications that I'm working on which is supposed to also be platform independent. So far, is UNIX/Windows compatible and it runs fine. However, maintaing this monster on VS2010 is a nightmare. I have the following file structure:
/
sources
lib1
include
...
src
...
lib2
include
...
src
...
app3
include
...
src
...
builders
cmake
...
make
...
VS2010
vs2010.sln
lib1
lib1.vcxproj
lib1.vcxproj.filters
lib2
lib2.vcxproj
lib2.vcxproj.filters
app3
app3.vcxproj
app3.vcxproj.filters
As we can see, because everything is platform independent, I had to completely separate the builders from sources. IMHO, that itself is a very good practice and it should be enforced by everyone :)
Here is the problem now... VS2010 is completely unusable when it comes to organize the include/sources files in filters. You have to do that manually by repeatedly doing "Add -> New Filter" followed by "Add -> Exiting Item". I have a VERY complex folder structure and files in each and every include folder. The task for creating the filters becomes a full day job. On the other hand, I could just drag the whole folder from Explorer onto the project inside VS2010 but it will put all header/source files in there without any filters, rendering it worthless: you can't possible search within 100 files for the right one without having some sort of hierarchy..
Question is:
Is VS2010 having some obscure way of importing a folder AND preserving the folder structure as filters? Looks to me that M$FT people who created VS2010 think that M$FT is the only animal in the jungle and you MUST pollute the sources folder with builders projects so you can leverage "show hiden files" to include them in the project along with the folder structure. That is absurd IMHO...
You are using CMake, so I advise you stick with only this. You can generate makefiles and VS2010 project files with it (at least). For VS, the generated files are a sln and a bunch of vxproj (one for each project in the CMake script).
In CMake file you can group files, using the command source_group. The filters will be automatically generated for vs according to the source groups. I don't know for other IDE like Code::Blocks or NetBeans.
If you want automatic grouping based on file path [Comment request]:
# Glob all sources file inside directory ${DIRECTORY}
file(GLOB_RECURSE TMP_FILES
${DIRECTORY}/*.h
${DIRECTORY}/*.cpp
${DIRECTORY}/*.c
)
foreach(f ${TMP_FILES})
# Get the path of the file relative to ${DIRECTORY},
# then alter it (not compulsory)
file(RELATIVE_PATH SRCGR ${DIRECTORY} ${f})
set(SRCGR "Something/${SRCGR}")
# Extract the folder, ie remove the filename part
string(REGEX REPLACE "(.*)(/[^/]*)$" "\\1" SRCGR ${SRCGR})
# Source_group expects \\ (double antislash), not / (slash)
string(REPLACE / \\ SRCGR ${SRCGR})
source_group("${SRCGR}" FILES ${f})
endforeach()

How can I build a C++ project with multiple interdependent subdirectories?

I have a C++ project where I've used directories as more of an organizational element -- the way one might use packages in Java or directories in PHP. Directories are not intended to be self-sufficient elements, but rather just a way of organizing the whole of the project and keeping me from being overwhelmed by sources. How can I construct my CMakeLists.txt files to deal with this? Making the directories libraries doesn't seem to fit here, since they are all interdependent and not intended to be used that way.
As a related issue, most of the examples I've seen of multiple subdirectories in CMake (and there aren't very many of those) have ignored or glossed over the issue of setting include_directories, which is something I've been having trouble with. Short of combing my source files to determine which file depends on which and in what directory, is there anyway to just set all directories under /src/ as potential include directories and let CMake work out which ones are actually dependent?
Here's an example structure:
--src
--top1
--mid1
--bot1
--src1.cpp
--hdr1.h
--bot2
--src2.cpp
--hdr2.h
--mid2
--bot3
--src3.cpp
--src4.cpp
--hdr3.h
--top2
--mid3
--src5.cpp
--hdr4.h
So on and so forth. How can I structure my CMakeLists.txt files to handle this sort of structure?
Since the directory structure in your project is just there to keep your files organized, one approach is to have a CMakeLists.txt that automatically finds all sources files in the src directory and also adds all directories as include directories that have a header file in them. The following CMake file may serve as a starting point:
cmake_minimum_required(VERSION 3.12)
project (Foo)
file (GLOB_RECURSE Foo_SOURCES CONFIGURE_DEPENDS "src/*.cpp")
file (GLOB_RECURSE Foo_HEADERS CONFIGURE_DEPENDS "src/*.h")
set (Foo_INCLUDE_DIRS "")
foreach (_headerFile ${Foo_HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list (APPEND Foo_INCLUDE_DIRS ${_dir})
endforeach()
list (REMOVE_DUPLICATES Foo_INCLUDE_DIRS)
add_executable(FooExe ${Foo_SOURCES})
target_include_directories(FooExe PRIVATE ${Foo_INCLUDE_DIRS})
The two file(GLOB_RECURSE ... commands determine the set of source and header files. The foreach loop computes the set of include directories from the list of all header files. The CONFIGURE_DEPENDS flags tells CMake to re-run the glob command at build time.
One drawback with computing the set of source files is that CMake will not automatically detect when new files are added to your source tree. You manually have to re-create your build files then.
Though #sakra gave a good answer to this question, I believe it is more proper to approach it more in depth.
We want to separate our code into modules and libraries for many reasons. Like code encapsulation, re usability, easier debugging etc. This idea would propagate in compiling process too.
In other word, we want to divide the compilation process into little compilation steps, each belong to one module. So every module must have its own compilation procedure. This is why we use one CMakeLists.txt file per directory. Hence every directory would have its own compilation commands and there would be one master CMakeLists.txt file in the root directory of your project.
Here is an example. Consider the following structure of a project:
src/
|
- main.cpp
|
_sum/
|
- sum.h
|
- sum.cpp
We would have one CmakeLists.txt Per directory. First directory is the root directory of the project which src/ folder is in it. here is content for that file:
cmake_minimum_required(VERSION 3.4)
project(multi_file)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-Wall")
add_subdirectory(src)
Next CMakeLists.txt would located in src/ directory:
add_subdirectory("sum")
add_executable(out main.cpp)
target_link_libraries(out sum)
And the last one will be in the sum/ directory:
add_library(sum SHARED sum.cpp)
I hope this helps. I created a github repository in case you feel you need to see the code or you need further explanation.
I'm not an expert on CMake but since there are no other answers I'll take a look at the documentaton and give it a go. Organizing source and include files in different directories is pretty much the norm.
It looks like CMake allows you to give a list of include directories:
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
So something like:
include_directories("src/top1/mid1/bot1" "src/top1/mid1/bot2/" ... )
These are passed to the compiler so it can find the header files and will be passed for each of the source files. So any of your source files should be able to include any of the header files (which I think is what you're asking for).
Similar to that you should be able to list all your source files in the add_executable command:
add_executable(name "src/top1/mid1/bot1/src1.cpp" "src/top1/id1/bot2/src2.cpp" ...)
So this would be a naive way of getting everything to build. Each source file will be compiled and will look for headers in all those directories and then the object files will get linked together. Consider if there is any way of simplifying this such that you don't need so many include folders, maybe there are only a few common header files that need to be referenced by all source files. If things get more complex you can buiild sub-hierarchies into libraries etc. Also consider seperating source files and headers (e.g. in src and include).