Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can someone explain this cmake script to me?

I feel like the entire cmake community is trolling me. None of the "tutorials" or resources make any sense to me. Its like I am missing something. I think what confuses me the most is the language and none of the tutorials I have seen come even close to being decent at explaining cmake to someone who has little unix and make experience.

Anyways, I am working with FireBreath and it uses cmake extensively, I think its time I start figuring out how to use it rather than changing the project files directly.

The root CMakeLists.txt file contains the following:

cmake_minimum_required (VERSION 2.6)
set (CMAKE_BACKWARDS_COMPATIBILITY 2.6)

Project(${PLUGIN_NAME})

file (GLOB GENERAL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
    [^.]*.cpp
    [^.]*.h
    [^.]*.cmake
    )

include_directories(${PLUGIN_INCLUDE_DIRS})

# Generated files are stored in ${GENERATED} by the project configuration
SET_SOURCE_FILES_PROPERTIES(
    ${GENERATED}
    PROPERTIES
        GENERATED 1
    )

SOURCE_GROUP(Generated FILES
    ${GENERATED}
    )

SET( SOURCES
    ${GENERAL}
    ${GENERATED}
    )

I would really appreciate it if someone could explain each line to me. Especially what ${GENERAL} and ${GENERATED} are.

like image 585
Mike Morum Avatar asked May 30 '11 06:05

Mike Morum


People also ask

What is a CMake script?

1. Basic CMake project CMake is a meta build system that uses scripts called CMakeLists to generate build files for a specific environment (for example, makefiles on Unix machines).

What is CMake good for?

CMake handles the difficult aspects of building software such as cross-platform builds, system introspection, and user customized builds, in a simple manner that allows users to easily tailor builds for complex hardware and software systems.

What language is Cmakelist TXT in?

Build process The build of a program or library with CMake is a two-stage process. First, standard build files are created (generated) from configuration files (CMakeLists.txt) which are written in CMake language.

How does CMakeLists TXT work?

CMakeLists. txt file contains a set of directives and instructions describing the project's source files and targets (executable, library, or both). When you create a new project, CLion generates CMakeLists. txt file automatically and places it in the project root directory.


2 Answers

First of all, the cmake syntax is really simple. It consists of "commands" and "arguments". It's so simple that it takes a while for it to sink in. Everything is "command(arguments)". Additionally, command names are case-insensitive. Previously they had to be ALL CAPS, but since version 2.6 (I think) it doesn't matter. Arguments however are case-sensitive.

cmake_minimum_required (VERSION 2.6)

This command sets the minimum required version of cmake for a project. If the current version of cmake is lower than 2.6 it will stop processing and report an error. This prevents having to support ancient versions of the tool.

set (CMAKE_BACKWARDS_COMPATIBILITY 2.6)

Set the variable CMAKE_BACKWARDS_COMPATIBILITY to the value 2.6. This is actually a minor bug in the CMakeLists.txt file you've presented, as CMAKE_BACKWARDS_COMPATIBILITY should not be used for 2.6 and above. The script should probably use cmake_policy. This is to specify how newer versions of cmake should behave when faced with inconsistencies in previous versions of cmake. Any scripts you write from scratch today wouldn't need to worry about this.

Project(${PLUGIN_NAME})

Sets the project name to the value of whatever is in the variable PLUGIN_NAME. This value is shown as the project name in some IDEs. To write a value to a variable, you can use set(PLUGIN_NAME myName) and to read the value you use the ${} syntax: "${PLUGIN_NAME}". Some commands also write to variables as well, but you use them the same way as in the set command.

file (GLOB GENERAL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
     [^.]*.cpp
     [^.]*.h
     [^.]*.cmake
     )

file is a command. Its first argument GLOB means "return files on disk whose names match the patterns I'll give as arguments". The next argument GENERAL is the variable that the result is stored to, like with set it writes the result to the variable and you can later read it with ${GENERAL}. RELATIVE and the path means return the file names relative to that path, not the complete path. So rather than "C:\some\long\path\src\foo.cpp" or "/home/me/some/path/src/foo.cpp" you would get "src\foo.cpp" or "src/foo.cpp". The variable CMAKE_CURRENT_SOURCE_DIR is a "magic variable" that CMake fills in for you and it refers to the path to the source directory currently being processed, where this CMakeLists.txt file lives. The last list of arguments are the patterns of files that will be matched. Basically, anything that has the file extension cpp, h or cmake.

include_directories(${PLUGIN_INCLUDE_DIRS})

Add the directories in ${PLUGIN_INCLUDE_DIRS} to those searched by the compiler for include files. This will result in extra "-I" arguments if you compile with gcc, for example.

# Generated files are stored in ${GENERATED} by the project configuration

Lines that start with # are comments.

SET_SOURCE_FILES_PROPERTIES(
       ${GENERATED}
       PROPERTIES
           GENERATED 1
       )

Files can have key/value pairs associated with them, and this affects how they are built. Here the files listed in the variable ${GENERATED} have the property "GENERATED" set to the value 1. What does that mean? Well, CMake now knows not to look for the files "${GENERATED}" on disk, as they will be created in another build step. In the snippet posted, nobody sets the variable ${GENERATED}. I imagine that it gets set elsewhere in the project files. Don't mix up the variable ${GENERATED} with the property GENERATED! This is a subtle point, and perhaps the variable should have been GENERATED_FILES to avoid confusion, i.e SET_SOURCE_FILES_PROPERTIES(${GENERATED_FILES} PROPERTIES GENERATED 1).

 SOURCE_GROUP(Generated FILES ${GENERATED})

This creates a group, which in Visual Studio translates into a file tab, called "Generated" that contains the files in the variable ${GENERATED}.

 SET(SOURCES ${GENERAL} ${GENERATED})

This line sets the variable SOURCES to whatever is in the variables ${GENERAL} and ${GENERATED}. Earlier we set ${GENERAL} to be the list of cpp, h and cmake files that were in the current source directory. In a C-like pseudo-code this is like "SOURCES = GENERAL + GENERATED". As a detail of implementation, the value SOURCES is actually a list and its contents are separated by ";" characters. Usually this is done so that later you can create a library or executable by just using the variable ${SOURCES} rather than repeating the other 2 variables everywhere.

like image 200
richq Avatar answered Sep 27 '22 22:09

richq


Sometimes, I can understand your feelings about the cmake tutorials. I recommend looking at the online docs and at some cmake-projects: E.g. Ogre, Vtk, Kde.

From the look of you CMakeLists.txt it appears that this one is supposed to be called by an outside CMake-project (with add_subdirectory), because it refers to the variables PLUGIN_NAME, PLUGIN_INCLUDE_DIRS and GENERATED.

To answer your questions:

cmake_minimum_required (VERSION 2.6)
set (CMAKE_BACKWARDS_COMPATIBILITY 2.6)
Project(${PLUGIN_NAME})

This prepares your cmakefile, tells cmake that it must be version 2.6 or higher and that you are starting a project with a name as specified in the PLUGIN_NAME variable.

file (GLOB GENERAL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
    [^.]*.cpp
    [^.]*.h
    [^.]*.cmake
    )

This part globs through the current source directory (the one where you cmakelists.txt is) and collects ALL *.cpp, *.h and *.cmake files. The result is a set/list of file paths, relative with resepct to the current source directory and is stored in a variable GENERAL.

# Generated files are stored in ${GENERATED} by the project configuration
SET_SOURCE_FILES_PROPERTIES(
    ${GENERATED}
    PROPERTIES
        GENERATED 1
    )

SOURCE_GROUP(Generated FILES
    ${GENERATED}
    )

Apparently, there will be a set of source-files stored in the variable GENERATED (thus not GENERAL). In case of build-generated source files, these files are not necessarily there at the first build of CMake and CMake will need to know these are generated. With the set_source_files_properties command, they get the "generated" property, which is needed for CMake to do correct dependency-checking.

SET( SOURCES
    ${GENERAL}
    ${GENERATED}
    )

So now we have a set of source files from the file( GLOB ... ) call, stored in the variable GENERAL. And we have a set of soruce files stored in the variable GENERATED which is created somewhere else. These two sets are combined into a single list of source-files and stored in the variable SOURCES.

Under normal circumstances I would expect an add_library call: add_library( ${PLUGIN_NAME} {SOURCES} )

This specifies to Cmake that a new library is to be created and built from the source-files in SOURCES.

like image 30
André Avatar answered Sep 27 '22 22:09

André