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

Cmake Use Tutorial (9) – About android cross compilation

Cmake Tutorial (10) – About File

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.

Introduction to the

The use of file in cmake is also very simple, similar to the C language file IO. The file command belongs to the script command and can be uninstalled from the script. Aux_source_directory is a project command and cannot be used in scripts.

First of all, I encountered a problem when writing programs. In the process of learning apUE, there are many instances of small programs, because IDE uses Clion, so you need to generate execution files in the cmake script, initially by simply adding add_executable commands to continuously add new programs. As I learned more, it became too cumbersome to add them manually, so I wrote a simple script semi-automatic build program with the following directory structure:

Those who qualify can qualify can go onto university. Those who qualify can qualify can go onto university. ├── cmakelists.txt ├─ part1 ├── cmakelists.txt │ ├── Copytest. C │ ├ ─ ─ the groupid. C │ ├ ─ ─ mycopy. C │ ├ ─ ─ myerror. C │ ├ ─ ─ myls. C │ ├ ─ ─ myshell. C │ ├ ─ ─ mystdcopy. C │ ├ ─ ─ │ ├── cmakels.txt │ ├── pthread.c │ ├─ pthread.c │ ├─ pthread.c │ ├─ pthread.c │ ├─ pthread.3 │ ├── cmakelists.txt │ ├── holets.c │ ├─ unp_1 │ ├─ cmakelists.txt │ ├── Daytimetcpcli. C │ ├ ─ ─ daytimetcpcliv6. C │ └ ─ ─ daytimetcpsrv. C └ ─ ─ unp_3 ├ ─ ─ CMakeLists. TXT └ ─ ─ byteorder. CCopy the code

SRC is the source code directory of the apue. It contains several sections and a main cmakelist file. Under the sections folder are the specific C and H files and a cmakelist file.

AUX_SOURCE_DIRECTORY(. PART_THREE)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
FOREACH (FILE ${PART_THREE})
    MESSAGE(STATUS ${FILE})
    STRING(REPLACE ". /" "" LIB_NAME ${FILE})
    STRING(REPLACE ".c" "" LIB_NAME ${LIB_NAME})
    add_executable(${LIB_NAME} ${FILE})
    target_link_libraries(${LIB_NAME} apue.a)
ENDFOREACH ()
Copy the code

The following two lines of code set the path for storing executable files and library files. Then the FOREACHE loop outputs all executable files and linked libraries. The executable file name is generated after the.c file replaces the useless information with a re.

Then add add_subdirectory(part3) to the main cMakelist and execute directly. And that’s what we’re going to talk about today.

File writing and appending

file(WRITE <filename> <content>...)
file(APPEND <filename> <content>...)
Copy the code

Write content to filename. If filename does not exist, a file is created. If filename contains a path, a folder is created. WRITE will erase the contents of the file and WRITE content again, and APPEND will APPEND the contents to the end of the file. Write a simple test:

file(WRITE test.txt "this is a test to wirte\n")
file(APPEND test/test.txt "this is a test to append")
file(APPEND test.txt "this is a test to append")
Copy the code

The directory structure is as follows:

.
└── write.cmake

0 directories, 1 file
Copy the code

After executing the script:

Those who qualify can qualify can go onto university. ➜ Stepfile git:(master) qualify cmake -p write. Cmake ➜ Stepfile git:(master) qualify treetest│ ── test.txt ├── test.txt ├── write.cmake 1 file, 3 filesCopy the code

Notice the difference between the configure_file command, which was introduced earlier and is used to replace the file contents while building the project.

File reading

file(READ <filename> <variable>
     [OFFSET <offset>] [LIMIT <max-in>] [HEX])
Copy the code

This is also simple: read the contents of filename to the variable, specify the value of OFFSET, which is where the reading started, specify the value of LISTMI, the length of the read, and whether HEX reads in hexadecimal or not.

file(STRINGS <filename> <variable> [<options>...] )Copy the code

Similar to reading character codes, but not bytecode. This command reads a string from filename into a variable, and a variable is a list, with each element holding the contents of each line. Binaries are not read and newlines are ignored. For example, the contents of the test.txt file we just wrote are:

this is a test to wirte
this is a test to append
    have tab # I added this manually
Copy the code

We read the file and print the result, writing the string. Cmake file as follows:

file(STRINGS test.txt strings)
foreach(str IN LISTS strings)
    message(STATUS ${str})
endforeach(str)
Copy the code

Since the results are stored in a list, we use a foreach loop to view the results:

-- this is a test to wirte
-- this is a test to append
-- have tab
Copy the code

For some of the options, not much is used:

OPTION instructions
LENGTH_MAXIMUM Maximum number of characters to read
LENGTH_MINIMUM Minimum number of characters to read
LIMIT_COUNT The maximum number of different characters to extract
LIMIT_INPUT Limits the maximum number of bytes read
LIMIT_OUTPUT Limits the maximum number of bytes that can be written to a variable
NEWLINE_CONSUME Do not ignore newlines
NO_HEX_CONVERSION Automatic conversion to hexadecimal is not required
REGEX Extract the string that matches the regular expression
ENCODING Recode UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE

Hash code of the file

file(<HASH> <filename> <variable>)
Copy the code

Use this command to extract the hash code of the file

MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512
Copy the code

If you’ve seen my Bomebrew tutorial, you need to fill in the SHA256 of the packaged file to verify the integrity of the downloaded file, so you can write a simple script using this to output hash values. Let’s write a simple example:

file(SHA256 test.txt hash)
message(STATUS ${hash})
Copy the code
-- f9bb70f1a2036a73f611858d01a8fb498efc7c83568faf0c74e5a52037492702
Copy the code

Collect files

file(GLOB <variable>
     [LIST_DIRECTORIES true|false] [RELATIVE <path>] [<globbing-expressions>...] ) file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS] [LIST_DIRECTORIEStrue|false] [RELATIVE <path>] [<globbing-expressions>...] )Copy the code

Two commands, starting with the first GLOB:

The GLOB command picks out all files that match

(optional, but not at all) and sorts them lexicographically by default.

file(GLOB files  *)
foreach(file IN LISTS files)
    message(STATUS ${file})
endforeach(file)
Copy the code

Select all files under the current file and print:

-- /Users/rangaofei/Documents/program/tutorial/Stepfile/filelist.cmake
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/hash.cmake
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/string.cmake
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/test
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/test.txt
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/write.cmake
Copy the code

In fact, the contents of this folder are as follows:

.filelist.cmake ├── hash.cmake ├─ string.cmake ├─test│ ── test.txt ├── test.txt ├── write.cmake 1 file, 6 filesCopy the code

Test is a folder, but the folder is printed in the script. If we don’t want the directory, we can set the LIST_DIRECTORIES to false (the default is true) and change the first line of code to look like this:

file(GLOB files  LIST_DIRECTORIES false *)
Copy the code
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/filelist.cmake
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/hash.cmake
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/string.cmake
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/test.txt
-- /Users/rangaofei/Documents/program/tutorial/Stepfile/write.cmake
Copy the code

If we don’t need an absolute path, but only a RELATIVE path to a folder, we can set RELATIVE to the folder. Modify the file as follows:

set(CUR ${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB files  LIST_DIRECTORIES false RELATIVE ${CUR}/.. *)
foreach(file IN LISTS files)
    message(STATUS ${file})
endforeach(file)
Copy the code

We set CUR as the current folder, and then set the relative path as the superior folder of the current folder, and the name of my current folder is Stepfile, then the output will contain the name of the current folder + file name:

-- Stepfile/filelist.cmake
-- Stepfile/hash.cmake
-- Stepfile/string.cmake
-- Stepfile/test.txt
-- Stepfile/write.cmake
Copy the code

That’s how it hurts. Also say this egg pain pseudo-regular match, the general file is enough.

*.cxx - matches all files ending in CXX *.vt? - Match all vTA,... F [3-5].txt - matches f3.txt, F4.txt, f5.txtCopy the code

Cmake does not officially recommend using GLOB to collect files, because if the cmakelists. TXT file is not changed in a project or module and files are deleted or added to a folder searched by file, cmake builds do not know about it and use the old list instead.

Let’s talk about the second one, GLOB_CURSE:

This command is used to list all files in subfolders and all current files. I don’t know how deep. The usage is basically the same as above, with the addition of the FOLLOW_SYMLINKS option. Before version 2.6.1, all files in the linked folder were also listed, because this caused some trouble, so this attribute was removed in the later version, and the link was treated as a file instead of listing the files in the linked folder. If you need to list, just add the FOLLOW_SYMLINKS parameter.

Cmake_minimum_required (VERSION 3.6)# if(POLICY CMP0009)
# cmake_policy(SET CMP0009 NEW)
# endif()
set(CUR ${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE files FOLLOW_SYMLINKS LIST_DIRECTORIES true RELATIVE ${CUR}/.. *)
foreach(file IN LISTS files)
    message(STATUS ${file})
endforeach(file)
Copy the code

This code will list all current files, files in subfolders, and files in links.

About AUX_SOURCE_DIRECTORY

aux_source_directory(<dir> <variable>)
Copy the code

Note that this command cannot be used in script; it is a project command.

Find all source files in dir folder and store them in variable. This command is different from previous commands because it only collects files in the current setting language. Cmake’s default setting language is C/CXX, so the only files that will be collected are those that are recognized by those languages, such as adding the following code to step

aux_source_directory(./ SRCLIST)
foreach(file IN LISTS SRCLIST)
  message(STATUS ${file})
endforeach(file)
Copy the code

The current directory structure is as follows

.├ ── cmakelists.txt ├── TutorialConfig.h.i.Exercises ─ Build ├─ tutorial.cxxCopy the code

Let’s see what the output is

-- ./tutorial.cxx
Copy the code

Only one file is included in the list.

File operation

file(RENAME <oldname> <newname>)
Copy the code

Rename a file or folder

file(REMOVE[<files>...] ) file(REMOVE_RECURSE [<files>...] )Copy the code

If the specified file is deleted, REMOVE_RECURSE will delete the file and folder without throwing an error if it does not exist.

file(MAKE_DIRECTORY [<directories>...] )Copy the code

Create files recursively, including folders in paths

file(RELATIVE_PATH <variable> <directory> <file>)
Copy the code

Calculate the relative path of file relative to directory and store it in variable. Similar to the previous collection file.

file(TO_CMAKE_PATH "<path>" <variable>)
file(TO_NATIVE_PATH "<path>" <variable>)
Copy the code

Convert between the cmake path and the local path. The cmake path uses /

file(DOWNLOAD <url> <file> [<options>...] ) file(UPLOAD <file> <url> [<options>...] )Copy the code

These two commands really tighten my ass to the limit. The first is to download the file named file from the URL, and the second is to upload the local file file to the URL. The following options apply to both commands

parameter instructions
INACTIVITY_TIMEOUT timeout
LOG Write the log to a variable
SHOW_PROGRESS According to schedule
STATUS a; bForm, a is the returned status code, b is the error code, if there are no errors, B is 0 (god knows, I didn’t try)
TIMEOUT Connection timeout
USERPWD : User name and password
HTTPHEADER The HTTP request header
EXPECTED_HASH ALGO= Validation algorithm (downloadable)
file(TIMESTAMP <filename> <variable> [<format>] [UTC])
Copy the code

Store the timestamp of the filename file in Varibale.

file(GENERATE OUTPUT output-file
     <INPUT input-file|CONTENT content>
     [CONDITION expression])
Copy the code

This command cannot be used in script and only works in project. In Tutorial 4, we used add_custom_command to add files at build time. Now, we have to choose between INPUT and CONTENT. The former is a file, and the second is a string. After version 3.10, INPUT uses the path relative to the current folder, and OUTPUT uses the path of the generated folder. In addition, the build file is executed only if the condition is true, and the value of the expression must return 0 or 1. If CMP0070 is set to new, it is the same as 3.10. If CMP0070 is set to old, it is the same as 3.10. If CMP0070 is set to old, it is the relative path.

Add in step1 in cdcMakelists.txt

if(POLICY CMP0070)
  cmake_policy(SET CMP0070 NEW)
endif()
file(GENERATE OUTPUT out.txt
     CONTENT "java"
     )
Copy the code

Out.txt is actually generated in the Build folder, and the contents are Java.

There are two more commands:

file(<COPY|INSTALL> <files>... DESTINATION <dir> [FILE_PERMISSIONS <permissions>...]  [DIRECTORY_PERMISSIONS <permissions>...]  [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS] [FILES_MATCHING] [[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS <permissions>...]] [...] )Copy the code

Copy and install the file to the specified destination folder.

The input file is a path relative to the current folder, and the destination folder is a path relative to the build folder.

COPY preserves the input file timestamp and optimizes the file if the same file already exists in the destination folder with the same timestamp. Permissions are reserved (the default is USE_SOURCE_PERMISSIONS) unless explicit permissions or NO_SOURCE_PERMISSIONS are given.

INSTALL is basically the same as COPY, but it outputs a INSTALL log and uses the NO_SOURCE_PERMISSIONS permission by default.

file(LOCK <path> [DIRECTORY] [RELEASE]
     [GUARD <FUNCTION|FILE|PROCESS>]
     [RESULT_VARIABLE <variable>]
     [TIMEOUT <seconds>])
Copy the code

Similar to a synchronization lock in Java.

If the [DIRECTORY] option is specified, the /cmake.lock file is locked; otherwise, the file is locked. GUARD is used to determine the scope. The default value is PROCESS. RELEASE is used to explicitly unlock.

If the TIMEOUT option is not specified, the system waits until the file is locked or a fatal error occurs. If set to 0, the lock operation is executed immediately and the status code is returned. If it is not set to 0, it waits for the corresponding time (in seconds) to lock.

If RESULT_VARIABLE is not set, any errors will prevent the program from running. If set, the result will be stored in Varobale, success will be 0, error will be stored error information.

Note that the lock is advisory – there is no guarantee that other processes will respect this lock, that is, locking synchronously two or more CMake instances that share some modifiable resource. Similar logic applies to the DIRECTORY option – locking a parent DIRECTORY does not prevent other LOCK commands from locking any subdirectories or files.

Attempts to lock a file twice are not allowed. If they don’t exist, any intermediate directories and files themselves will be created. Ignore the GUARD and TIMEOUT options in the RELEASE operation.