Cmake windows hello world

In this article, you’ll learn how to create a CMake hello world project from scratch using the CMake Tools extension in VS Code.

If you have an existing CMake project that already has a CMakeLists.txt file in the root directory but no CMake presets, you can skip to Create a CMakePresets.json file to configure your project with CMake presets.

Otherwise, create a folder for a new project. From the Terminal window, create an empty folder called HelloWorld, navigate into it, and open VS Code in that folder by entering the following commands:

mkdir helloworld
cd helloworld
code .

The code . command opens VS Code in the current working folder, which becomes your «workspace».

Create a CMakeLists.txt file

The CMake Tools extension can create the files for a basic CMake project for you.

  1. Open the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)) and run the CMake: Quick Start command:

    Create CMake quickstart

  2. Enter a project name, and select C++ as the project language.

    This information will be written to CMakeLists.txt and a few initial source files.

    Note: If you had other source code files in this folder that you wanted to add as targets to the CmakeLists.txt, an option to add these would now be given. But for this tutorial, we will stick with just the hello world file.

  3. Select CTest as an additional option to add support for testing. You can also select CPack for CPack support.

    Additional Options

  4. Next, select Executable as the project type to create a basic source file (main.cpp) that includes a basic main() function.

    Choose project type

    Note: If you had wanted to create a basic source and header file, you would have selected Library instead. But for this tutorial, Executable will do. If you are prompted to configure IntelliSense for the folder, select Allow.

This successfully creates the CMakeLists.txt file, which tells the CMake tools how to build your project.

Project contents

Create a CMakePresets.json file

Next, continue with the CMake Quick Start to create a CMakePresets.json file.

  1. Select Add a New Preset and Create from Compilers.

    The extension automatically scans for kits on your computer and creates a list of compilers found on your system.

  2. Select the compiler you want to use.

    For example, depending on the compilers you have installed, you might see something like this:

    Add a new preset

  3. Enter a name for this new preset.

    The name for the preset will be written to CMakePresets.json.

After completing these steps, you should now have a complete hello world CMake project that contains the following files: main.cpp, CMakeLists.txt, and CMakePresets.json.

Add a new preset

5/29/2024

Уровень сложностиПростой

Время на прочтение6 мин

Количество просмотров4.2K

Всем привет! На написание данной статьи меня толкнула суровая реальность и лень разбираться с английскими текстами о том, что и куда жмать, дабы собрать адекватный проект на CMake.

Установка CMake тут не рассматривается, вот ссылки:

офф сайт

гайд по установке

Все будет происходить из-под Windows, структурно мало чем будет отличаться от Linux, кроме команд для сборки.

Для начала предлагаю разобраться со структурой проекта в целом:

|Проект №1
|
|CMakeLists.txt #этот лист находится в корне и описывает все группы проектов и папок 
|
|--подпроект №1
|----CMakeLists.txt #листы внутри проекта описывают, 			
|----*.cpp 	        #то как этот проект должен собраться
|----*.h  
|
|--подроект №2
|----CMakeLists.txt 
|----*.cpp
|----*.h  
|
|... (еще кучка проектов)
|
|--include  #эта папка содержит те хеддеры библиотек, 
|----*.h	#которые мы в дальнейшем будем использовать для проектов
|
|--build  	#как устроена эта папка, может решаться по разному
            #хранит скомпилированные фалы (exe lib dll)
            #также эта папка хранит кучу сгенерированных файлов CMake

Надеюсь, прочитав данную статью, вы сможете собрать проекты такого формата, но для начала возьмем что-то попроще (старый добрый «Hello World!»).

//hello.cpp
#include <iostream>

int main()
{
	std::cout << "Hello world from cmake!"<< std::endl;
	return 0;
}

Структура проекта:

|CMakeLists.txt
|
|--hello_world_dir
|----hello.cpp
|
|--build

CMakeLists.txt — это файлы (скрипты) конфигурации проекта, благодаря им мы можем собирать наших проекты. Сейчас мы разберем его простейшую структуру и разберем подходы к сборке проекта.

cmake_minimum_required(VERSION %тут могла быть ваша цифра%) #показывает какой минимальной версией можно собрать проект

project(hello_world) #дает имя проекту

#дает понять что будет собираться исполняеый файл(exe)
#первый аргумент - это название собираемоего проекта, остальные исходные файлы *.h *.cpp
#все аргументы записываются через пробел
add_executable(hello_world hello_world/hello.cpp) 

Итак, у нас готов скрипт для сборки нашего первого проекта, рассмотрим же подходы к сборке:

  1. собрать все в корневой директории вместе с исходниками {фатальная ошибка};

  2. собрать все в отдельно созданной директории для сборки проекта.

Минусы первого подхода достаточно хорошо объясняют, почему так лучше не делать:

  • трудности с сохранением разных сборок проекта

  • захламление корневой директории

Последний шаг: Сборка

Ну а теперь нам нужно залезть в любимый терминал или командную строку. Переходим в корень проекта.

Если просто написать:

cmake

То нам скажут как инициализировать проект или пересобрать его, ну и про --help упомянут, для получения большей информации

Usage

  cmake [options] <path-to-source>
  cmake [options] <path-to-existing-build>
  cmake [options] -S <path-to-source> -B <path-to-build>

Specify a source directory to (re-)generate a build system for it in the
current working directory.  Specify an existing build directory to
re-generate its build system.

Run 'cmake --help' for more information.

Я предлагаю использовать вариант cmake [options] -S <path-to-source> -B <path-to-build. Ключ -S устанавливает директорию с исходниками, обязательно содержащую файл CMakeLists.txt
Ключ -B устанавливает директорию куда будет собираться наш проект. В этой директории будут служебные файлы CMakeCashe и файлы *.sln для с проектов в VisualStudio, а также директории подпроектов (в Linux данная директория содержит MakeFile)

cmake -S . -B build

Теперь, можно уже и скомпилировать, пишем:

cmake --build <папка содержащая CMakeCache.txt>

В нашем случае данной папкой является build.

cmake --build build

Поздравляю, Вы собрали свой первый проект!

Для такого простого проекта кажется, что все это сплошное нагромождение, поэтому переходим к более сложному проекту.

Проект будет состоять из нашей самописной библиотеки и проекта, который использует эту библиотеку. (весь код будет на github)

Структура проекта:

|
|CMakeLists.txt #основной скрипт сборки, в котором объявляются стандарты языка, 
|               #места хранения скомпилированных файлов, подключение общих зависимостей
|               #подключаются каталоги подпроектов, 
|
#подкпроект библиотеки
|--our_lib 
|----CMakeLists.txt #скрипт сборки подпроекта 			
|----*.cpp 		 
|----*.h
|
#подпроект программы использующей библиотеку
|--samples
|----CMakeLists.txt 
|----*.cpp
|----*.h  
|
#директория с хедарами нашей библиотеки
|--include   
|----*.h	
|
|--build 

Рассмотрим CMakeLists в корне

cmake_minimum_required(VERSION %Ваша цифра%)

set(PROJECT_NAME <имя проекта>)
project(${PROJECT_NAME})

#настраиваем стандарты языка
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

#настраиваем места хранения скомпилированных файлов
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE})

#даем названия подпроектам 
set(PROG_LIBRARY "${PROJECT_NAME}") 

#сораняем путь до директории include нашими хедарами 
set(PROG_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include")

#добавляет путь до нашей директории в область видимости всех проектов
include_directories(${PROG_INCLUDE})

#добавляем директории наших подпроектов в область видимости CMake 
add_subdirectory(src)
add_subdirectory(samples)

Команды cmake_minimum_required и project нам уже знакомы. Многочисленная set(<имя>, <значение>) — создает переменные и объявляет их значения. Благодаря переменным, получается более модифицируемые и универсальные скрипты сборки, также, изменяя значения служебных переменных самого CMake, проект обретает определенные свойства, например: используемый стандарт языка, места хранения скомпилированных файлов и т.д. Перечислять смысл каждой не вижу, так как большинство из них имеют говорящие названия.

${имя_переменной} — такая конструкция позволяет использовать значение переменных.

include_directories(список путей) — добавляет директории в область поиска хедеров в проекте.

add_subdirectory(путь до директории) — добавляет в проект поддиректорию в которой обязательно должен быть файл CMakeLists.txt. В нашем случае это папки с проектом библиотеки и проектом, ее использующим.

Стоит заметить, что все переменные, объявленные в скрипте вызывающем команду, доступны для поддиректорий.

Скрипты сборки в подпроектах нам в целом уже знакомы, для начала рассмотрим библиотечный (/src/CMakeLists.txt).

Пользуясь опытом Hello World, можно написать этот скрипт так:

add_library(${PROG_LIBRARY} STATIC <список всех исходников>)

add_library(<имя> <тип библиотеки> <список исходников>) — команда аналогичнаяadd_executable, только для библиотек. (STATIC — статические библиотеки, SHARED — динамические).

Да, проект соберется, но постоянно прописывать весь список исходников руками то еще удовольствие, поэтому немного модифицируем скрипт:

set(target ${PROG_LIBRARY})

file(GLOB hdrs "*.h")      #команда для работы с файлами
file(GLOB srcs "*.cpp")

add_library(${target} STATIC ${srcs} ${hdrs} )

file() — команда для работы с файлами, у нее есть множество возможных параметров позволяющих: читать, редактировать, находить,создавать, удалять, загружать …
file(GLOB <имя переменной> <регулярное выражение>) — ищет файлы в текущей директории подходящие регулярному выражению и сохраняет результат в переменную.

Таким образом, скрипт сам ищет исходные файлы (хедеры и cpp) и в add_library мы просто используем значения сохраненные в переменных.

В Cmake подпроекты называются target (таргетами — целями), поэтому я добавил одноименную переменную для удобства.

Скрипт проекта, использующего библиотеку отличается одной строчкой.

set(target sample)

file(GLOB hdrs "*.h")
file(GLOB srcs "*.cpp")

add_library(${target} STATIC ${srcs} ${hdrs} )
target_link_libraries(${target} ${PROG_LIIBRARY})

target_link_libraries(<имя таргета> <список подключаемых библиотек>) — подключает библиотеки к выбранному таргету.

Ну и теперь стандартная процедура инициализации и сборки. (не забудьте переместиться в корень или указать правильные пути)

cmake -S . -B build
cmake --build build

Ура, более сложный проект создан и собран!Но, а что если возникли какие-то проблемы во время компиляции отдельного подпроекта(таргета), можно как-то обойтись без сборки всего проекта?

МОЖНО!

cmake --build -t <имя таргета>

Надеюсь, данная статья дала хорошее начало в изучении сборки на CMake.

Как закрепление материала предлагаю подключить вам юнит тесты для нашей самописной библиотеки (гугл тесты). Данную библиотеку можно скомпилировать самому, как отдельную часть проекта, а можно воспользоваться официальным гайдом, чтобы загрузить код непосредственно репозитория (более сложный вариант, дополнительные ссылки будут прикреплены ниже)

helloworld-cmake

This sample is showing you how you can use cmake and CMakeLists.txt file to compile your c++ application.

Environment Setup

Make sure g++ installed. If not go to Build and run your first application with g++ for more help.

Also make sure make command is installed. If not go to Build and run your first application with make for more help.

Run following command to see if cmake is installed:

$ cmake --version
zsh: command not found: cmake

If you face command not found: cmake that means it is not there.

Installing make

  • MacOS
  • Linux
    • Debian/Ubuntu

Building Hello World application

Create a folder called build and then use cmake command to build the application. It uses Makefile compile the sources to object files.

$ mkdir build
$ cd build
$ cmake .. -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CC_COMPILER=gcc
-- The C compiler identification is AppleClang 10.0.1.10010046
-- The CXX compiler identification is AppleClang 10.0.1.10010046
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/g++
-- Check for working CXX compiler: /usr/bin/g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
CMake Warning:
  Manually-specified variables were not used by the project:

    CMAKE_CC_COMPILER

-- Build files have been written to: /Users/nkabiliravi/git/mycpptutorial/helloworld-cmake/build

Now use cmale —build command link the object files into a file called greet:

You can also use make command:

$ make
Scanning dependencies of target greet
[ 33%] Building CXX object CMakeFiles/greet.dir/hello.cpp.o
[ 66%] Building CXX object CMakeFiles/greet.dir/main.cpp.o
[100%] Linking CXX executable greet
[100%] Built target greet

Running the app

Run greet command like this:

$ ./bin/greet
Hello World!

Visit Build and run your first application with cmake to learn more about this sample.

Example

Given a C++ source file main.cpp defining a main() function, an accompanying CMakeLists.txt file (with the following content) will instruct CMake to generate the appropriate build instructions for the current system and default C++ compiler.

main.cpp (C++ Hello World Example)

#include <iostream>

int main()
{
    std::cout << "Hello World!\n";
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.4)

project(hello_world)

add_executable(app main.cpp)

See it live on Coliru

  1. cmake_minimum_required(VERSION 2.4) sets a minimum CMake version required to evaluate the current script.

  2. project(hello_world) starts a new CMake project.
    This will trigger a lot of internal CMake logic, especially the detection of the default C and C++ compiler.

  3. With add_executable(app main.cpp) a build target app is created, which will invoke the configured compiler with some default flags for the current setting to compile an executable app from the given source file main.cpp.

Command Line (In-Source-Build, not recommended)

> cmake .
...
> cmake --build .

cmake . does the compiler detection, evaluates the CMakeLists.txt in the given . directory and generates the build environment in the current working directory.

The cmake --build . command is an abstraction for the necessary build/make call.

Command Line (Out-of-Source, recommended)

To keep your source code clean from any build artifacts you should do «out-of-source» builds.

> mkdir build
> cd build
> cmake ..
> cmake --build .

Or CMake can also abstract your platforms shell’s basic commands from above’s example:

> cmake -E make_directory build
> cmake -E chdir build cmake .. 
> cmake --build build 

Building is a fairly general term without strict definition; It usually refers to the whole process that outputing the final product (an executable or a library) from source materials. Depending on the requirements, building will involve several of the following: pre-processing, compiling, linking, converting data files, automatically testing, packaging.

Among the tools that defining the building behaviors for Platform Dependent products whose programming language usually be C or C++, CMake is the most popular one as it is open-source and cross-platform. The building process with CMake takes place in two stages:

  1. Given abstract, platform and compiler independent building procedures defined by developers, generating standard Makefile or Project Files for IDEs (Visual Studio, Xcode etc.) .
  2. Invoke the desired native build tool to undertake the actual building process.

Here we introduce the usage of CMake. The environment of this tutorial is Windows 10; The output of each command will be different from that running on Linux. For the syntax of CMake Language, you may visit CMake Syntax for details.

Hello World

The following is a good starting point for learning about CMake.

  1. Create a new folder test.
  2. Under the directory, create the source file main.cpp.
    1
    2
    3
    4
    5
    #include <stdio.h>
    int main(){
    printf("Hello World from test Main!\n");
    return 0;
    }
  3. Create the CMake file named exactly CMakeLists.txt
    1
    2
    3
    cmake_minimum_required(VERSION 3.10)
    project(Main)
    add_executable(Main main.cpp)
  4. Run cmake . to generate native project files. Under Windows, CMake will generate a Visual Studio project by default. When finished, lots of contents created in the directory:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    │  ALL_BUILD.vcxproj
    │ ALL_BUILD.vcxproj.filters
    │ CMakeCache.txt
    │ CMakeLists.txt
    │ cmake_install.cmake
    │ main.cpp
    │ Main.sln
    │ Main.vcxproj
    │ Main.vcxproj.filters
    │ ZERO_CHECK.vcxproj
    │ ZERO_CHECK.vcxproj.filters
    └─CMakeFiles/
  5. Run cmake --build . to create executable. You could find the Main.exe in <root-dir>/Debug.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    │  ALL_BUILD.vcxproj
    │ ALL_BUILD.vcxproj.filters
    │ CMakeCache.txt
    │ CMakeLists.txt
    │ cmake_install.cmake
    │ main.cpp
    │ Main.sln
    │ Main.vcxproj
    │ Main.vcxproj.filters
    │ ZERO_CHECK.vcxproj
    │ ZERO_CHECK.vcxproj.filters
    ├─CMakeFiles/
    ├─Debug/
    │ Main.exe
    │ Main.ilk
    │ Main.pdb
    ├─Main.dir/
    └─x64/
  6. Run executable via Debug\Main.exe
    1
    Hello World from test Main!

Explanation

Generate a Project Buildsystem

To generate a buildsystem with CMake, the following must be defined:

  • Source Tree: The top-level directory containing source files provided by the project. Then the generation will start with CMakeLists.txt under this directory.
  • Build Tree: The top-level directory where buildsystem files and output artifacts being placed. CMake will also create a CMakeCache.txt here to store persistent information.
  • Generator: The type of buildsystem to generate. If not specified, CMake will choose the proper one automatically. When using one of the Command-Line Build Tool Generators CMake expects that the environment needed by the compiler toolchain is already configured in the shell. When using one of the IDE Build Tool Generators, no particular environment is needed.

You could run CMake with one of the following command signatures to specify them.

  1. cmake [<options>] <path-to-source>: Then the current directory is the build tree, <path-to-source> is the source tree. Both absolute an relative path is valid. The source tree must contain a CMakeLists.txt file and must not contain a CMakeCache.txt file.
  2. cmake [<options>] <path-to-existing-build>: Then <path-to-existing-build> is the build tree which must contain a CMakeCache.txt file because CMake will load the source tree from it.
  3. cmake [<options>] -S <path-to-source> -B <path-to-build>. Specify both <path-to-build> and <path-to-source>. The source tree must contain a CMakeLists.txt file; The build tree will be created automatically if it does not already exist.

Options

For the full list of options please visit https://cmake.org/cmake/help/latest/manual/cmake.1.html#options or cmake --help

  • -C <initial-cache>: Pre-load a script that contains a list of set() commands to initialize the cache values. The loaded entries take priority over the project’s default values.
  • -D <var>:<type>=<value> or -D <var>=<value>: Create or update a CMake CACHE entry.
  • -G <generator-name> Specify a build system generator. Run cmake --help to get the name of supported generators
  • --log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>: Set the log level. The message() command will only output messages of the specified log level or higher. The default log level is STATUS.

Build a Project

Use cmake --build <dir> [<options>] [-- <build-tool-options>] to build an already-generated project binary tree.

  • --build <dir> The binary directory when building.
  • --parallel [<jobs>], -j [<jobs>]: Specify the maximum number of concurrent processes. If <jobs> is omitted, use the default number.
  • --target <tgt>..., -t <tgt>...: Build specific <tgt>s .
  • --config <cfg>: For multi-configuration tools, choose specific <cfg>.
  • --clean-first: Clean existing built target and re-build it.
  • -target clean: Clean existing built target only.

Output message

message([SEND_ERROR|STATUS|FATAL_ERROR|DEBUG|TRACE] "message text" ...)

CMake displays STATUS to TRACE messages on stdout with prefix --; All other message types are sent to stderr. FATAL_ERROR will terminate the process immediately whereas CMake Error stops generation only but continues processing.

Set Project Name

project(<PROJECT-NAME> [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]])

This command will set the name of the project and store it in PROJECT_NAME. When called from the top-level CMakeLists.txt, it will also store the project name in CMAKE_PROJECT_NAME. Simultaneously, the variables PROJECT_SOURCE_DIR, <PROJECT-NAME>_SOURCE_DIR, PROJECT_BINARY_DIR, <PROJECT-NAME>_BINARY_DIR will be defined according to the absolute path of the corresponding directory.

Add Executable

add_executable(<name> [source1] [source2 ...])

This command will add an executable target called <name> to be built from the source files listed in the command invocation; The source files can also be added later using target_sources(). The <name> must be globally unique within a project. By default the executable will be created in the build tree directory with the name <name> or <name>.exe depending on the native platform.

In-Source and Out-of-Source Build

Some build trees created with GNU autotools have a make distclean command that removes Makefiles and others belonging to the generated build system. However, CMake has no way to track exactly which files are generated by itself. Therefore, it’s recommended to adopt the out-of-source build —- placing the build tree separately from the source tree. Then one can clean the build by clear or delete the build tree without affect the original source files.

A Better Hello World

Reorganize the Project Directory

  1. Create src/ to place source files
  2. Create CMakeLists.txt under src/
  3. Create build/ to place buildsystem

After that, the structure of our project will be

1
2
3
4
5
6
7
|   CMakeLists.txt
|
+---build
| \---bin
\---src
CMakeLists.txt
main.cpp

Config Source and Binary Directory

1
add_subdirectory(source_dir [binary_dir])

This command will add source_dir run its CMakeLists.txt; A relative path will be evaluated with respect to the current directory. The binary_dir specifies the directory in which to place the output files. Both relative path and absolute path are valid; A relative path it will be evaluated with respect to the current output directory. If binary_dir is not specified, the value of source_dir before expanding will be used.

In top-level CMakeLists.txt become:

1
2
3
cmake_minimum_required(VERSION 3.10)
project(Main)
add_subdirectory(src/ main)

Config Source Directory

It’s tedious to list all source files manually, regardless of using

1
add_executable(project source1.c source2.c)

or

1
2
set(DIR source1.c source2.c)
add_executable(project ${DIR})

aux_source_directory(<dir> <variable>) will collects the names of all the source files in <dir> and stores the list in the <variable>. Note that there is no way for the build system that knows when a new source file has been added; When a new source is just added to the directory, one would have to manually rerun CMake to generate a build system incorporating the new file.

In CMakeLists.txt of src/, add

1
2
aux_source_directory(. SRC_DIR)
add_executable(Main ${SRC_DIR})

Config Binary Directory

In CMakeLists.txt of src/, add

1
2
3
aux_source_directory(. SRC_DIR)
add_executable(Main ${SRC_DIR})
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

Specify the C++ Standard

In top-level CMakeLists.txt, add

1
2
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

Add a Version Number

Add the version number in project.

1
project(Main VERSION 1.0)

Then the 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 will be defined accordingly.

It’s also valid to specify the version number directly in the source code,; Using CMakeLists.txt provides more flexibility. Under src/, create a new file config.h.in with the following content:

1
2


configure_file(<input> <output>) will copy the <input> to an <output> file with the evaulated values referenced as @VAR@ or ${VAR}. Each variable reference will be replaced with the current value of the variable, or the empty string if the variable is not defined.

The configured file will be written into the ${CMAKE_CURRENT_BINARY_DIR}; We must add that directory to the list of paths to search for include files. In src/CMakeLists.txt, add

1
2
configure_file(config.h.in config.h)
target_include_directories(Main PUBLIC ${PROJECT_BINARY_DIR})

target_include_directories(<target> <INTERFACE|PUBLIC|PRIVATE> [items1...]) [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]) specifies include directories to when compiling a given target. The named <target> must have been defined by such as add_executable() or add_library().

Finally, in main.cpp, let’s include the header file and print the version number.

1
2
3
4
5
6
7
#include <stdio.h>
#include <config.h>
int main(){
printf("Hello World from test Main!\n");
printf("The Major Version is %s and the Minor Version is %s\n" , PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
return 0;
}

A Complex Hello World

Add Math Library

Create math/ under src/, add CMakeLists.txt, MathFunctions.cpp with MathFunctions.h

MathFunctions.h

1
extern double power(double base, int exponent);

MathFunctions.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "MathFunctions.h"
double power(double base, int exponent)
{
int result = base;
int i;
if (exponent == 0) {
return 1;
}
for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}

src/math/CMakeLists.txt

1
aux_source_directory(. DIR_LIB_SRCS)

After that, the structure will be

1
2
3
4
5
6
7
8
9
10
11
12
|   CMakeLists.txt
|
+---build
\---src
| CMakeLists.txt
| config.h.in
| main.cpp
|
\---math
CMakeLists.txt
MathFunctions.cpp
MathFunctions.h

Build and Use Static Library

In src/math/CMakeLists.txt, add

1
2
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library (MathFunctions ${DIR_LIB_SRCS})

add_library(<name> [STATIC | SHARED] [source1] [source2 ...]) will add a library target called <name>.

The top-level CMakeLists.txt become:

1
2
3
4
cmake_minimum_required(VERSION 3.10)
project(Main VERSION 1.0)
add_subdirectory(src/math math)
add_subdirectory(src/ main)

The src/CMakeLists.txt become:

1
2
3
4
5
6
7
8
aux_source_directory(. SRC_DIR)
add_executable(Main ${SRC_DIR})

configure_file(config.h.in config.h)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

target_link_libraries(Main PUBLIC MathFunctions)
target_include_directories(Main PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/math)

The structure become

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|   CMakeLists.txt
| compile.bat
| README.txt
|
+---build
| +---bin
| | \---Debug
| | Main.exe
| | Main.ilk
| | Main.pdb
| |
| \---lib
| \---Debug
| MathFunctions.lib
| MathFunctions.pdb
|
\---src
| CMakeLists.txt
| config.h.in
| main.cpp
|
\---math
CMakeLists.txt
MathFunctions.cpp
MathFunctions.h

Build and use Dynamic Library

src/math/CMakeLists.txt become

1
2
3
aux_source_directory(. DIR_LIB_SRCS)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library (MathFunctions SHARED ${DIR_LIB_SRCS})

MathFunctions.h become

1
extern  __declspec( dllexport )  double power(double base, int exponent);

src/CMakeLists.txt become:

1
2
3
4
5
6
7
8
9
aux_source_directory(. SRC_DIR)
add_executable(Main ${SRC_DIR})

configure_file(config.h.in config.h)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

link_directories(${PROJECT_SOURCE_DIR}/lib/Debug)
target_link_libraries(Main PUBLIC MathFunctions)
target_include_directories(Main PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/math)

Then the structrue become

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|   CMakeLists.txt
|
+---build
| +---bin
| | \---Debug
| | Main.exe
| | Main.ilk
| | Main.pdb
| |
| \---lib
| \---Debug
| MathFunctions.dll
| MathFunctions.exp
| MathFunctions.ilk
| MathFunctions.lib
| MathFunctions.pdb
|
\---src
| CMakeLists.txt
| config.h.in
| main.cpp
|
\---math
CMakeLists.txt
MathFunctions.cpp
MathFunctions.h

When running with dynamic-linked library, you should put the .dlls under the same folder of .exe.

https://cmake.org/cmake/help/latest/guide/tutorial/ https://cliutils.gitlab.io/modern-cmake/

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Как открыть мой компьютер в windows 10 комбинация клавиш
  • Gta vice city skachat dlya kompyuter windows 10
  • Кодовым названием windows 95 было
  • Windows media player не воспроизводит файлы vob
  • Что за программа antimalware service executable в windows 10