众所周知,很难获得有关CMake作为初学者的任何有用信息.到目前为止,我已经看过一些关于如何设置一些非常基本的项目的教程.然而,这些都没有解释其中所显示的任何东西背后的推理,总是留下许多洞来填补.
在CMakeLists上调用CMake 意味着什么?是应该每个构建树调用一次还是什么?如果它们都使用来自同一来源的相同CMakeLists.txt文件,如何为每个构建使用不同的设置?
为什么每个子目录都需要自己的CMakeLists文件?在CMakeLists.txt文件上使用CMake而不是项目根目录下的文件是否有意义?如果是这样,在什么情况下?
指定如何从他们自己的子目录中的CMakeLists.txt文件构建可执行文件或库与在所有源的根目录中的CMakeLists.txt文件中执行它之间的区别是什么?
我可以为Eclipse创建一个项目,为Visual Studio创建另一个项目,只需-G在调用CMake时更改选项吗?这甚至是如何使用的?
到目前为止,我所看到的教程,文档页面或问题/答案都没有给出有关理解如何使用CMake的有用见解.这些例子并不彻底.无论我读什么教程,我都觉得我错过了一些重要的东西.
像我这样的CMake新手提出的许多问题都没有明确地提出这个问题,但这显然表明,作为新手,我们不知道如何处理CMake或者如何处理它.
lei*_*paC 115
根据维基百科:
CMake是用于使用独立于编译器的方法管理软件构建过程的软件.它旨在支持依赖于多个库的目录层次结构和应用程序.它与本机构建环境(如make,Apple的Xcode和Microsoft Visual Studio)结合使用.
使用CMake,您不再需要维护特定于编译器/构建环境的单独设置.您有一个配置,适用于许多环境.
CMake可以从相同的文件生成Microsoft Visual Studio解决方案,Eclipse项目或Makefile迷宫,而无需更改其中的任何内容.
给定了一堆包含代码的目录,CMake管理所有依赖项,构建订单以及项目在编译之前需要完成的其他任务.它实际上并没有编译任何东西.要使用CMake,您必须告诉它(使用名为CMakeLists.txt的配置文件)您需要编译哪些可执行文件,它们链接到哪些库,项目中有哪些目录以及它们内部的内容,以及标记等任何详细信息或者你需要的任何其他东西(CMake非常强大).
如果这是正确设置的,那么您可以使用CMake创建所需的"本机构建环境"所需的所有文件.在Linux中,默认情况下,这意味着Makefile.因此,一旦你运行CMake,它将创建一堆文件供自己使用加上一些Makefiles.此后您需要做的就是每次编辑代码时从根文件夹在控制台中键入"make",然后生成编译和链接的可执行文件.
这是我将在整个过程中使用的示例项目设置:
simple/
CMakeLists.txt
src/
tutorial.cxx
CMakeLists.txt
lib/
TestLib.cxx
TestLib.h
CMakeLists.txt
build/
Run Code Online (Sandbox Code Playgroud)
稍后将显示和讨论每个文件的内容.
CMake根据项目的根目录 CMakeLists.txt设置项目,并cmake在控制台中执行的任何目录中执行.从不是项目根目录的文件夹执行此操作会产生所谓的源外构建,这意味着在编译期间创建的文件(obj文件,lib文件,可执行文件,您知道)将被放置在所述文件夹中,与实际代码分开.它有助于减少混乱,也是其他原因的首选,我不会讨论.
我不知道如果你cmake在root以外的任何地方执行会发生什么CMakeLists.txt.
在这个例子中,因为我希望它全部放在build/文件夹中,首先我必须在那里导航,然后传递CMake根目录CMakeLists.txt所在的目录.
cd build
cmake ..
Run Code Online (Sandbox Code Playgroud)
默认情况下,正如我所说,这会使用Makefile设置所有内容.以下是build文件夹现在应该是什么样子:
simple/build/
CMakeCache.txt
cmake_install.cmake
Makefile
CMakeFiles/
(...)
src/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
lib/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
Run Code Online (Sandbox Code Playgroud)
这些文件都是什么? 您唯一需要担心的是Makefile和项目文件夹.
注意src/和lib/文件夹.这些是因为simple/CMakeLists.txt使用命令指向它们而创建的add_subdirectory(<folder>).此命令告诉CMake在所述文件夹中查找另一个CMakeLists.txt文件并执行该脚本,因此以这种方式添加的每个子目录都必须包含一个CMakeLists.txt文件.在此项目中,simple/src/CMakeLists.txt描述了如何构建实际的可执行文件并simple/lib/CMakeLists.txt描述了如何构建库.CMakeLists.txt默认情况下,描述的每个目标都将放置在构建树的子目录中.所以,快点之后
make
Run Code Online (Sandbox Code Playgroud)
在控制台完成后build/,添加了一些文件:
simple/build/
(...)
lib/
libTestLib.a
(...)
src/
Tutorial
(...)
Run Code Online (Sandbox Code Playgroud)
项目已构建,可执行文件已准备好执行.如果您希望将可执行文件放在特定文件夹中,您会怎么做? 设置适当的CMake变量,或更改特定目标的属性.有关CMake变量的更多信息.
以下是源目录中每个文件的内容:
simple/CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(Tutorial)
# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)
Run Code Online (Sandbox Code Playgroud)
应始终设置所需的最低版本,根据警告CMake抛出时不要.使用你的CMake版本.
您可以在以后使用项目名称,并提示您可以从同一CMake文件管理多个项目.不过,我不会深入研究这个问题.
如前所述,add_subdirectory()向项目添加一个文件夹,这意味着CMake希望它有一个CMakeLists.txt内部,然后在继续之前运行.顺便说一句,如果您碰巧定义了CMake函数,则可以从CMakeLists.txt子目录中的其他s 使用它,但您必须在使用之前定义它,add_subdirectory()否则它将无法找到它.但是,CMake对于图书馆来说更聪明,所以这可能是你遇到这种问题的唯一时间.
simple/lib/CMakeLists.txt:
add_library(TestLib TestLib.cxx)
Run Code Online (Sandbox Code Playgroud)
要创建自己的库,请为其命名,然后列出它构建的所有文件.直截了当.如果它需要另一个文件,foo.cxx要编译,你会改为写add_library(TestLib TestLib.cxx foo.cxx).例如,这也适用于其他目录中的文件add_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx).稍后将详细介绍CMAKE_SOURCE_DIR变量.
您可以用另一件事来指定您想要一个共享库.例子:add_library(TestLib SHARED TestLib.cxx).不用担心,这就是CMake开始让你的生活更轻松的地方.无论是否共享,现在您只需要处理使用以这种方式创建的库的名称就是您在此处提供的名称.此库的名称现在是TestLib,您可以从项目的任何位置引用它.CMake会找到它.
是否有更好的方法来列出依赖项? 肯定是的.请查看下面的更多相关信息.
simple/lib/TestLib.cxx:
#include <stdio.h>
void test() {
printf("testing...\n");
}
Run Code Online (Sandbox Code Playgroud)
simple/lib/TestLib.h:
#ifndef TestLib
#define TestLib
void test();
#endif
Run Code Online (Sandbox Code Playgroud)
simple/src/CMakeLists.txt:
# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)
# Link to needed libraries
target_link_libraries(Tutorial TestLib)
# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)
Run Code Online (Sandbox Code Playgroud)
该命令的add_executable()工作原理完全相同add_library(),当然,它会生成一个可执行文件.现在可以将此可执行文件作为目标引用target_link_libraries().由于tutorial.cxx使用TestLib库中的代码,因此您将其指向CMake,如图所示.
类似地,任何源中的任何.h文件#included add_executable()都不会以某种方式添加到与源相同的目录中.如果不是target_include_directories()命令,则lib/TestLib.h在编译Tutorial时找不到,因此整个lib/文件夹被添加到要搜索#includes的include目录中.您可能还会看到include_directories()以类似方式执行的命令,除了它不需要您指定目标,因为它完全为所有可执行文件设置目标.我再一次解释CMAKE_SOURCE_DIR.
simple/src/tutorial.cxx:
#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
test();
fprintf(stdout, "Main\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意如何包含"TestLib.h"文件.不需要包含完整的路径:CMake负责处理所有幕后工作target_include_directories().
从技术上讲,在一个简单的源代码树这样你可以不用做CMakeLists.txt是S lib/和src/,只是添加类似add_executable(Tutorial src/tutorial.cxx)到simple/CMakeLists.txt.这取决于您和您项目的需求.
查找和使用包:这个问题的答案解释得比我更好.
使用控制流等声明变量和函数:查看本教程,该教程解释了CMake所提供的基础知识,以及一般的优秀介绍.
CMake变量:有很多,所以接下来是让你走上正确轨道的速成课程.CMake wiki是获取更多关于变量和表面上其他东西的更深入信息的好地方.
您可能希望编辑某些变量而无需重建构建树.使用ccmake(它编辑CMakeCache.txt文件).记得c在完成更改后进行配置,然后g使用更新的配置使用makefile.
阅读以前引用的教程以了解使用变量,但长话短说:
set(<variable name> value)更改或创建变量.
${<variable name>}使用它.
CMAKE_SOURCE_DIR:源的根目录.在前面的示例中,这始终等于/simpleCMAKE_BINARY_DIR:构建的根目录.在前面的示例中,这等于simple/build/,但是如果您cmake simple/从诸如的文件夹中运行foo/bar/etc/,则CMAKE_BINARY_DIR该构建树中的所有引用都将成为/foo/bar/etc.CMAKE_CURRENT_SOURCE_DIR:当前CMakeLists.txt所在的目录.这意味着它在整个过程中发生变化:从simple/CMakeLists.txtyield中打印出来/simple,然后从simple/src/CMakeLists.txtyield中打印出来/simple/src.CMAKE_CURRENT_BINARY_DIR:你明白了.此路径不仅取决于构建所在的文件夹,还取决于当前CMakeLists.txt脚本的位置.为什么这些重要?源文件显然不在构建树中.如果您尝试类似于target_include_directories(Tutorial PUBLIC ../lib)前面示例中的内容,那么该路径将相对于构建树,也就是说它将像写入一样${CMAKE_BINARY_DIR}/lib,它将在内部查找simple/build/lib/.那里没有.h文件; 最多你会发现libTestLib.a.你想要的${CMAKE_SOURCE_DIR}/lib.
CMAKE_CXX_FLAGS:传递给编译器的标志,在本例中是C++编译器.另外值得注意的是CMAKE_CXX_FLAGS_DEBUG,如果CMAKE_BUILD_TYPE设置为DEBUG ,将使用哪个.还有更多这样的; 查看CMake wiki.CMAKE_RUNTIME_OUTPUT_DIRECTORY:告诉CMake在构建时放置所有可执行文件的位置.这是一个全球性的环境.例如,您可以将其设置为bin/并将所有内容整齐地放置在那里.EXECUTABLE_OUTPUT_PATH是相似的,但不赞成使用,以防您偶然发现它.CMAKE_LIBRARY_OUTPUT_DIRECTORY:同样,一个全局设置告诉CMake放置所有库文件的位置.目标属性:您可以设置仅影响一个目标的属性,无论是可执行文件还是库(或存档......您都明白了).这是一个如何使用它的一个很好的例子set_target_properties().
有没有一种简单的方法可以自动将源添加到目标? 使用GLOB列出同一变量下给定目录中的所有内容.示例语法是FILE(GLOB <variable name> <directory>/*.cxx).
你能指定不同的构建类型吗?是的,虽然我不确定这是如何工作或限制的.它可能需要一些if/then'ning,但是CMake确实提供了一些基本的支持而没有配置任何东西,比如默认值CMAKE_CXX_FLAGS_DEBUG.您可以通过CMakeLists.txt文件在文件中设置构建类型,也可以通过set(CMAKE_BUILD_TYPE <type>)从控制台调用CMake并使用适当的标志来设置构建类型cmake -DCMAKE_BUILD_TYPE=Debug.
使用CMake的项目的任何好例子?维基百科有一个使用CMake的开源项目列表,如果你想研究它.到目前为止,在线教程对我来说只是令人失望,但是这个Stack Overflow问题有一个非常酷且易于理解的CMake设置.值得一看.
在代码中使用CMake中的变量:这是一个快速而肮脏的示例(改编自其他一些教程):
simple/CMakeLists.txt:
project (Tutorial)
# Setting variables
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 1)
# Configure_file(<input> <output>)
# Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
# So you can pass some CMake variables to the source code (in this case version numbers)
configure_file (
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
)
Run Code Online (Sandbox Code Playgroud)
simple/TutorialConfig.h.in:
// Configured options and settings
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
Run Code Online (Sandbox Code Playgroud)
生成的文件由CMake生成,simple/src/TutorialConfig.h:
// Configured options and settings
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 1
Run Code Online (Sandbox Code Playgroud)
通过巧妙地使用这些,你可以做很酷的事情,如关闭图书馆等.我建议你看一下这个教程,因为有一些稍微高级的东西,对于大型项目来说,迟早会非常有用.
对于其他一切,Stack Overflow充满了特定的问题和简洁的答案,这对除了没有经验的人以外的所有人都很有用.
| 归档时间: |
|
| 查看次数: |
15560 次 |
| 最近记录: |