Cmake (cmake)

Cmake Use tutorial (1) – start

Cmake Tutorial 2 – Adding libraries

Cmake use tutorial (3) – installation, testing, system self – check

Cmake Use tutorial (4) – file generator

Cmake Use tutorial (5) -cpack generate installation package

Cmake Use tutorial (6) – lousy syntax

Cmake Use Tutorial (7) – Processes and loops

Cmake: Macro and Function

This series of articles was translated from the official Cmake tutorial: CMake Tutorial.

Example program address: github.com/rangaofei/t…

It will not stop at the official tutorial. I as an Android developer, is really no Linux C program development experience, hope big guys forgive. The tutorial is done on MacOS, and I’ve tested most Linux as well, so IF there are special instructions, I’ll note them. This tutorial is based on cmake-3.10.2 and assumes that you have cmake installed.

“It’s not just grammar, it’s documentation.”

Cmake File format

The command format in this section follows the following syntax:

format annotation
<command> Mandatory
[command] It can be written or not written
a\|b Either A or B will do

Cmake recognizes files in the cMakelists. TXT and *. Cmake formats. Cmake can organize files in three ways:

category The file format
Dierctory(Folder) CMakeLists.txt
Script(script) <script>.cmake
Module(modules) <module>.cmake

This series focuses on the syntax of cmakelists.txt, but I’ll write the awful scripts and modules if I have to.

1. Directory

When CMake processes a project, the entry point is a source file called cMakelists.txt, which must be cMakelists.txt in the root directory. This file contains the build specifications for the entire project, and when we have multiple subfolders to compile, use the add_subdirectory(

) command to add subdirectories to the build. Each subdirectory added must also contain a cMakelists. TXT file as an entry point for that subdirectory. When the cMakelists. TXT file for each subdirectory is processed, CMake generates the corresponding directory in the build tree as the default working and output directory. It’s critical to keep this in mind so that we can use an external build instead of having to use a painful internal build every time and then delete a bunch of files to build anew.

2. Script

A single

3. Module

In Directory or Script, the CMake code can use the include() command to load.cmake. Cmake has a number of built-in modules to help us build projects, such as CheckFunctionExists, mentioned in the previous article. You can also supply your own modules and specify their locations in the CMAKE_MODULE_PATH variable.

Cmake basic writing format

Let’s look at the way it’s defined

The name of the expression I think the example
space <match '[ \t]+'> Any space or TAB a b
newline <match '\n'> A newline a\nb
line_comment '#' <any text not starting in a bracket_argument and not containing a newline> Starts with ‘#”, is not in the ‘[]’ block, does not contain newlines #bus
separation space\|newline Spaces or newlines a b=a\nb
lineending linecomment? newline Nothing from the beginning of the comment to the newline character is executed
command_invocation space* identifier space* '(' arguments ')'
quoted_argument "quoted_element* " Parameters wrapped in quotation marks “a”

This looks like a pain in the ass, so LET me just write the simplest one

add_executable(hello world.c foo.c) # This is a comment
Copy the code

Is equal to the

add_executable(hello 
                world.c 
                foo.c)
# This is a comment
Copy the code

Easy as it is. Note that the argument section can be enclosed in quotes, which represents one argument. If the line is not complete, the \\ symbol is used to indicate that the line is joined, or no quotes are used. However, if the argument has a delimiter, it is considered multiple arguments.

Define variables

The common function for defining variables is set(KEY VALUE), and undefining variables is unset(KEY). Their values are always string, and some commands may interpret strings as other types of values. Variable names are case sensitive and can contain any text, but we recommend using only alphanumeric characters with names like _ and -.

The scope of a variable is basically the same as in Java, so I won’t explain it much.

The variable reference is of the form ${variable_name} and is judged among the referenced or unreferenced arguments. The variable reference is replaced by the value of the variable, or by an empty string if the variable is not set. Variable references can be nested and replaced internally, for example, ${outer_${inner_variable} verunavailable}. Environment variables are referenced in the form $ENV{VAR} and are referenced as normal variables in the same context.

Cmake builds the system

So this is kind of entering the text. Bullshit introduction is not much to say, direct dry goods.

Executable files and libraries are defined using the add_executable() and add_library() commands. The generated binaries have appropriate prefixes, suffixes, and extensions for the platform. The dependencies between binary targets are represented by the target_link_libraries() command.

add_library(archive archive.cpp zip.cpp lzma.cpp)
add_executable(zipapp zipapp.cpp)
target_link_libraries(zipapp archive)
Copy the code

When building C programs, add_executable is required to generate executable files. Add_library is required when building the Android dynamic library because jNI calls the dynamic library.

External building

This will generate a series of cached files in the current directory. If we need to delete these files if we need to rebuild, cmakecache.txt must be deleted, otherwise we will not build the latest program. Let’s see what happens when we run cmake in the project root directory:

 ~/Desktop/Tutorial/Step1/ tree-l 1. ├── cmakecache.txt ├── CMakeFiles ├─ cmakelists.txt ├── Makefile ├─ Tutorial ├── TutorialConfig.h ├── TutorialConfig.h.n ├── cmake_install.cmake ├─ tutorialCopy the code

The generated files are interlaced with the source files and are rather confusing. We can use an external build to separate the source files from the generated files, and when we need to clear the cache and rebuild the project, we can delete everything in this folder and reruns the build commands to keep the source files clean, making it easier to manage the project.

Start by creating a new folder called Build. This folder is the directory we use to store the generated files, then go to that directory and execute the build command.

mkdir build # Create build directory
cd build Go to the Build directory
cmake .. Because the program entry build file is in the root directory of the project, use the relative path of the upper directory to use the build file in the root directory
Copy the code

At this point, you can see that the generated files are all in the Build folder, and the build is complete.

 ~/Desktop/Tutorial/Step1/ tree-l 2. ├── cmakelists.txt ├─ build ├── CMakeCache. TXT ├─ build ├─ CMakeCache CMakeFiles │ ├── Makefile │ ├── tutorialconfig.h │ ├── cmake_installCopy the code

Future project presentations will use all external builds.

Here is the code I wrote to explain some of the basic instructions

Cmake_minimum_required (VERSION 2.6) Project (Tutorial) Message (STATUS)${PROJECT_NAME})
message(STATUS ${PROJECT_SOURCE_DIR})
message(STATUS ${PROJECT_BINARY_DIR})
message(STATUS ${Tutorial_SOURCE_DIR})
message(STATUS ${Tutorial_BINARY_DIR})
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")

# add the executable
add_executable(Tutorial tutorial.cxx)
Copy the code
  • Message is similar to a tool for logging to the console, but it is a little more powerful, and in some modes can terminate the build.
message([<mode>] "message to display"...).Copy the code

Mode The following modes are available

model role
(none) Important information
STATUS Incidental information
WARNING CMake Warning, continue processing
AUTHOR_WARNING CMake Warning (dev), continue processing
SEND_ERROR CMake Error, continue processing,but skip generation
FATAL_ERROR CMake Error, stop processing and generation
DEPRECATION CMake Deprecation Error or Warning if variable CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED is enabled, respectively, else no message.

STATUS is something we use a lot.

  • Look at the first line:
Cmake_minimum_required (VERSION 2.6)Copy the code

Set the minimum required version of Cmake for a project, and update the policy Settings to match the given version (I’ll never get into policy Settings). This command is needed to build a project or a library. The syntax looks like this

cmake_minimum_required(VERSION major.minor[.patch[.tweak]]
                       [FATAL_ERROR])
Copy the code

The version number must specify the primary and secondary code, please ignore the optional [FATAL_ERROR] option, it is completely useless.

If you specify a version number greater than the cmake version you installed, the build will stop and an error will be thrown:

CMake Error at CMakeLists.txt:1 (cmake_minimum_required):
  CMake 3.11 or higher is required.  You are running version 3.10.2


-- Configuring incomplete, errors occurred!
Copy the code

cmake_minimum_requiredMust be called at the beginning of the project root, i.eproject()Before. This directive can also be called within function(), where the scope is limited to the function, but only if it does not affect global use

  • Let’s go to the second row
project (Tutorial)
Copy the code

Specify the name of the project as Tutorial, which must be used for building projects, but not for building libraries. The document is as follows:

project(<PROJECT-NAME> [LANGUAGES] [<language-name>...] ) project(<PROJECT-NAME> [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] [DESCRIPTION <project-description-string>] [LANGUAGES <language-name>...] )Copy the code

Set the project name and store it in the PROJECT_NAME variable. Four variables are also specified:

PROJECT_SOURCE_DIR, <PROJECT-NAME>_SOURCE_DIR
PROJECT_BINARY_DIR, <PROJECT-NAME>_BINARY_DIR
Copy the code

But we usually just use the former one, which makes it easier to change. In the above code we output the information about these variables with message, and the log output after executing the build command:

-- Tutorial
-- /Users/saka/Desktop/Tutorial/Step1
-- /Users/saka/Desktop/Tutorial/Step1/build
-- /Users/saka/Desktop/Tutorial/Step1
-- /Users/saka/Desktop/Tutorial/Step1/build
Copy the code

You can see that these variables do print the correct values.

We can also specify the version number directly when specifying the project name, if not specified, the version number is null. The version number is stored in the following variables:

PROJECT_VERSION, <PROJECT-NAME>_VERSION
PROJECT_VERSION_MAJOR, <PROJECT-NAME>_VERSION_MAJOR
PROJECT_VERSION_MINOR, <PROJECT-NAME>_VERSION_MINOR
PROJECT_VERSION_PATCH, <PROJECT-NAME>_VERSION_PATCH
PROJECT_VERSION_TWEAK, <PROJECT-NAME>_VERSION_TWEAK
Copy the code

Usually we recommend using the former one. To test this, change the code in the cMakelists.txt file:

Project (Tutorial VERSION 1.2.3 DESCRIPTION"this is description"
	LANGUAGES CXX)
message(STATUS ${PROJECT_VERSION})
message(STATUS ${PROJECT_VERSION_MAJOR})
message(STATUS ${PROJECT_VERSION_MINOR})
message(STATUS ${PROJECT_VERSION_PATCH})
message(STATUS ${PROJECT_VERSION_TWEAK})
message(STATUS ${PROJECT_DESCRIPTION})
Copy the code

The output log is as follows:

-- 1.2.3
-- 1
-- 2
-- 3
-- 
-- this is description
Copy the code

Setting the version number here has the same effect as setting the version number with set, taking the last value set. Since we did not specify the tweak version, this is empty and we see that the description is stored in the PROJECT_DESCRIPTION variable.

LANGUAGES can be set to C, CXX(C ++), Fortran, etc. If not set, C and CXX are enabled by default. Setting it to NONE, or writing only the LANGUAGES keyword instead of the specific source language, skips enabling any language. C or C ++ programs are usually compiled with cmake, so use the default.

  • Let’s look at the important lineconfigure_file

This command is used to copy a file to another location and modify the contents of the file. The syntax is as follows:

configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
Copy the code

Copy the file to the file and replace the variable values @var @ or ${VAR} in the input file contents. Each variable reference is replaced with the current value of the variable, or an empty string if the value of the variable is not defined. (VAR must be maintained with variables in cmakelist.txt, otherwise comments will be generated.)

The input file is defined as:

#cmakedefine VAR ..
Copy the code

The contents of the generated file after configure are replaced with:

#define VAR ... // The replacement succeeded/ *#undef VAR */ // undefined variable
Copy the code

The generated file will retain Spaces and tabs between ‘#’ and ‘cMakedefine’.

One thing to note here is that clion now uses cmake by default to build programs, but cMakedefine is not supported in Clion, so you can simply fill in #define VAR… To write the macro definition, producing exactly the same result. Cmakedefine # : cmakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # : cMakedefine # Use #define or #cmakedefine with as little space as possible.

If absolute paths are not specified, they are set by default to CMAKE_CURRENT_SOURCE_DIR and CMAKE_CURRENT_BINARY_DIR, which are the project root directory and the build directory.

COPYONLY copies the file, does not replace anything, and cannot be used with NEWLINE_STYLE

ESCAPE_QUOTES disallows escaping as “. If there is a\”b “in the variable without this command, the generated file will use the escaped character a”b.

${VAR} = ${VAR} = ${VAR} = ${VAR}

NEWLINE_STYLE

Here’s an example: foo

#cmakedefine FOO_ENABLE
#cmakedefine FOO_STRING "@FOO_STRING@"
Copy the code

Add code to cmakelists.txt to set a switch that executes the statement in if:

option(FOO_ENABLE "Enable Foo" ON)
if(FOO_ENABLE)
  set(FOO_STRING "foo")
endif()
configure_file(foo.h.in foo.h @ONLY)
Copy the code

The generated file foo.h

#define FOO_ENABLE
#define FOO_STRING "foo"
Copy the code

If option(FOO_ENABLE “Enable Foo” ON) is set to off, option(FOO_ENABLE “Enable Foo” ON), then the if statement is not executed and the following file is generated:

/ *#undef FOO_ENABLE *// *#undef FOO_STRING */
Copy the code
  • include_directoriesThis line

Add the current binary directory to the compiler search include directory, so you can directly use the header files generated in the previous step.

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...] )Copy the code

Adds the given directory to the directory that the compiler uses to search for files. The relative path is relative to the current root directory.

The directories in parentheses are added to the INCLUDE_DIRECTORIES attribute of the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target attribute for each target in the current CMakeLists file.

By default, the specified directory is appended to the current list of include directories. You can change this default behavior by setting CMAKE_INCLUDE_DIRECTORIES_BEFORE to ON. By explicitly using AFTER or BEFORE, you can choose to add and pre-set.

If the SYSTEM option is given, the compiler is told that these directories on some platforms refer to the directories contained by the SYSTEM.

The translation really taught me big head.