CMAKE实践读书笔记(3)P18-P25

 

目录

INSTALL_FILES

再谈CMAKE_INSTALL_PREFIX和./configure --prefix=

CMAKE_INSTALL_PREFIX和DESTDIR/PREFIX的区别

vi是什么

CMAKE_INSTALL_PREFIX 的默认定义是/usr/local

 什么是函数的声明

SET(LIBRARY_OUTPUT_PATH <路径>)

再谈ADD_LIBRARY

模块库(共享库插件)是什么

.x文件格式

SET_TARGET_PROPERTIES

GET_TARGET_PROPERTY(VAR target property)

CLEAN_DIRECT_OUTPUT

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)


INSTALL([[SCRIPT <file>] [CODE <code>]] [...])

INSTALL命令还支持安装自定义的脚本,使用SCRIPT选项或CODE选项指定。可以使用SCRIPT选项指定要安装的脚本文件的路径,或者使用CODE选项指定要安装的脚本代码。

以下是INSTALL命令使用SCRIPT选项的示例:

INSTALL(SCRIPT install-script.cmake)

这将安装名为install-script.cmake的脚本文件。

以下是INSTALL命令使用CODE选项的示例:

INSTALL(CODE "MESSAGE(\"Installing my project...\")")

这将安装一个简单的脚本,它只是打印一条消息。


INSTALL_FILES

INSTALL_FILES 不是一个有效的 CMake 命令。CMake 中有一条 INSTALL(FILES) 命令,用于将文件安装到指定的目的地,但没有 INSTALL_FILES 命令。


再谈CMAKE_INSTALL_PREFIX和./configure --prefix=

假设我们有一个C++项目,它包含一个源文件main.cpp和一个头文件hello.h,我们希望将生成的可执行文件安装到/usr/local/bin目录下。

CMakeLists.txt文件内容如下:

cmake_minimum_required(VERSION 3.5)

project(MyProject)

# 添加可执行文件
add_executable(myapp main.cpp)

# 安装可执行文件到/usr/local/bin目录下
install(TARGETS myapp DESTINATION /usr/local/bin)

在命令行中执行以下命令:

mkdir build
cd build
cmake -D CMAKE_INSTALL_PREFIX=/usr/local ..
make
sudo make install

通过这个示例,我们使用CMAKE_INSTALL_PREFIX指定了安装路径,并使用install指令将生成的可执行文件安装到了指定的路径下。

假设你的源代码目录为/path/to/source,以下是使用./configure --prefix=/usr/local配置安装路径的示例:

cd /path/to/source
./configure --prefix=/usr/local
make
sudo make install

其中,./configure是根据configure脚本生成Makefile,--prefix=/usr/local指定了安装路径为/usr/localmake根据Makefile编译源代码生成可执行文件和库文件。sudo make install将可执行文件和库文件安装到指定路径/usr/local


CMAKE_INSTALL_PREFIX和DESTDIR/PREFIX的区别

  • CMAKE_INSTALL_PREFIX:表示安装目录的根路径,用于指定安装的根目录。比如,如果你指定了CMAKE_INSTALL_PREFIX为/usr/local,那么所有的安装路径都会在/usr/local下面,比如可执行文件会被安装到/usr/local/bin,库文件会被安装到/usr/local/lib等等。
  • DESTDIR和PREFIX:是旧式的安装方式,和CMAKE_INSTALL_PREFIX有些类似。DESTDIR表示目标根目录,PREFIX表示安装路径的根路径。它们都是为了兼容旧式的Makefile安装方式而存在的。在使用它们时,make install命令会将生成的文件先复制到DESTDIR/PREFIX下,然后再复制到实际的安装路径下。比如,如果你指定了DESTDIR为/tmp,PREFIX为/usr,那么make install会先将文件复制到/tmp/usr下面,然后再将它们复制到实际的安装路径下。

总的来说,CMAKE_INSTALL_PREFIX是CMake的一种新式安装方式,更加直观和灵活,而DESTDIR和PREFIX则是一种旧式的安装方式,使用起来比较麻烦。


cd /backup/cmake/t2
mkdir doc
vi doc/hello.txt

这个命令是在 /backup/cmake/t2 目录下创建一个名为 doc 的文件夹,然后打开文本编辑器 vi 并创建一个名为 hello.txt 的文件,该文件位于 doc 文件夹中。


vi是什么

vi 是一个常用的文本编辑器,在Unix和Linux系统中非常常用。它有两种模式:命令模式和编辑模式。在命令模式下,你可以进行复制、剪切、粘贴、查找、替换等操作;在编辑模式下,你可以编辑文本内容。 vi 非常强大,可以处理各种文本文件。


cmake -DCMAKE_INSTALL_PREFIX=/tmp/t2/usr ..

".."表示上级目录,因此"cmake -DCMAKE_INSTALL_PREFIX=/tmp/t2/usr .."的意思是,在上级目录中查找CMakeLists.txt文件,并将构建目录设置为当前目录,并且将CMAKE_INSTALL_PREFIX选项设置为/tmp/t2/usr。


CMAKE_INSTALL_PREFIX 的默认定义是/usr/local


//hello.c 内容如下:
#include “hello.h”
void HelloFunc()
{
    printf(“Hello World\n”);
}
//hello.h 内容如下:
#ifndef HELLO_H
#define HELLO_H
#include <stdio.h>
void HelloFunc();
#endif

这是一个典型的C语言程序的分离式编译过程。头文件hello.h中包含了函数声明,而函数定义则在源文件hello.c中实现。在编译时,编译器只需要使用头文件中声明的函数,而不需要知道实现的细节。这种分离式编译的好处是可以使代码更加模块化,方便代码维护和更新。此外,头文件的作用还包括提供常量定义、宏定义、结构体、枚举类型等,为源代码提供方便的使用。

虽然在 hello.c 中也需要使用 printf 函数,但是实际上这个函数的声明已经在 stdio.h 中进行了定义。这就意味着,如果我们在 hello.c 中再次包含 stdio.h,会导致重复定义的错误。因此,我们只需要在 hello.h 头文件中包含 stdio.h 即可,这样在编译时就可以通过头文件的包含来获取到 printf 函数的声明。

hello.c中写#include <stdio.h>也是可以的,不过这样会使得stdio.h这个头文件在每次引用hello.c时都被重新包含一次,导致编译时间增加,效率降低。为了避免这种情况,通常将需要包含的头文件放在头文件中,而在源文件中只包含必要的头文件。这样能够提高编译效率,也有助于代码的维护。

c源文件中要包含自己的头文件_源文件需不需要自包含_神秘博士来袭的博客-CSDN博客


 什么是函数的声明

函数的声明是指在函数调用之前提前声明函数的返回类型、函数名和参数类型等信息,以便编译器在编译过程中检查函数调用是否正确。函数的声明通常写在头文件中,并在需要调用该函数的源文件中包含该头文件。例如:

// 声明函数
int add(int a, int b);

int main() {
    int result = add(1, 2);  // 调用函数
    return 0;
}

// 定义函数
int add(int a, int b) {
    return a + b;
}

在上面的代码中,int add(int a, int b) 是函数的声明,告诉编译器函数名、返回值类型和参数类型。在 main 函数中调用 add 函数时,编译器能够根据声明确定调用方式是否正确。实际的函数定义在 add.c 文件中,通过包含头文件来实现声明与定义的分离。


SET(LIBRARY_OUTPUT_PATH <路径>)

SET(LIBRARY_OUTPUT_PATH <路径>) 用于设置编译生成的库文件的输出路径。

例如,设置库文件的输出路径为/usr/local/lib,可以使用以下指令:

SET(LIBRARY_OUTPUT_PATH /usr/local/lib)

这样,编译生成的库文件就会被输出到/usr/local/lib目录下。


再谈ADD_LIBRARY

ADD_LIBRARY指令是CMake中用于添加一个新的库(静态库或动态库)的指令。它的语法如下:

ADD_LIBRARY(<name> [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL]
            source1 [source2 ...])

其中,name 表示新库的名称;SHAREDSTATICMODULE分别表示新库的类型为动态库、静态库、模块库(共享库插件);EXCLUDE_FROM_ALL表示将该库从默认的all构建中排除;source1source2等表示新库所依赖的源文件。

例如,如果我们要添加一个名为 hello 的库,包含两个源文件 hello.cppworld.cpp,我们可以使用以下指令:

ADD_LIBRARY(hello SHARED hello.cpp world.cpp)

该指令将在当前目录下创建一个名为 libhello.so 的动态库,并包含 hello.cppworld.cpp 两个源文件。


模块库(共享库插件)是什么

模块库(也称为共享库或动态链接库)是一种可重定位的二进制文件,其包含了一些可供程序在运行时使用的代码和数据。与静态库不同,模块库的代码在程序运行时动态加载,因此它们更加灵活,可以减小可执行文件的大小并且使程序的更新和维护更为容易。

模块库通常包含可重复使用的代码,这些代码可以在多个程序中共享,从而避免了重复编写相同代码的工作。在使用模块库时,程序会在运行时链接到库中的代码,并且在需要时加载它们。由于模块库的代码是可重定位的,因此它们可以被加载到内存中的任何地址,并且可以在多个程序之间共享。

在编写程序时,可以使用现有的模块库,也可以编写自己的模块库。许多操作系统和编程语言都支持模块库的使用,例如Windows上的DLL(动态链接库),Linux上的SO(共享对象)和MacOS上的dylib(动态库)等。

MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。


.x文件格式

在Linux和Unix等系统中,静态库和共享库都可以使用.x扩展名,但它并不代表一种特定的格式,只是文件扩展名的一种约定。


SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES是CMake中的一条命令,用于设置指定目标的属性。该命令可以用于设置各种属性,如输出名称、库类型、编译选项、链接选项等。

具体来说,SET_TARGET_PROPERTIES命令可以用于以下方面:

1.设置生成目标的输出名称,即生成的二进制文件名。

2.设置生成目标的库类型,如静态库、动态库等。

3.设置生成目标的编译选项,如编译器选项、宏定义等。

4.设置生成目标的链接选项,如链接库的路径、链接选项等。

使用SET_TARGET_PROPERTIES的基本语法如下:

SET_TARGET_PROPERTIES(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)

其中,target1、target2等参数表示要设置属性的目标,可以是库或可执行文件。prop1、prop2等参数表示要设置的属性名称,value1、value2等参数表示要设置的属性值。

例如,以下命令设置一个名为mylib的静态库的输出名称为mylib_static:

ADD_LIBRARY(mylib STATIC src1.c src2.c)
SET_TARGET_PROPERTIES(mylib PROPERTIES OUTPUT_NAME mylib_static)

在这个例子中,ADD_LIBRARY命令创建了一个名为mylib的静态库,包含src1.c和src2.c两个源文件。SET_TARGET_PROPERTIES命令设置了mylib的输出名称为mylib_static。

除了OUTPUT_NAME属性外,SET_TARGET_PROPERTIES还支持许多其他属性,具体可以参考CMake官方文档。


GET_TARGET_PROPERTY(VAR target property)

GET_TARGET_PROPERTY是CMake中的一条命令,用于获取指定目标(target)的属性(property)值,并将其存储到变量(VAR)中。

例如,以下命令将获取名为my_target的目标的输出路径属性值并将其存储到my_output_path变量中:

GET_TARGET_PROPERTY(my_output_path my_target RUNTIME_OUTPUT_DIRECTORY)

此命令执行后,变量my_output_path将包含my_target的输出路径属性值。如果该属性未设置,则该变量将为空。


CLEAN_DIRECT_OUTPUT

CLEAN_DIRECT_OUTPUT是一个CMake的目标属性。将该属性设置为1时,构建过程不会将输出文件复制到构建树的根目录。而是将输出文件放在指定的位置,以避免与其他同名目标的库发生冲突。

具体来说,当CLEAN_DIRECT_OUTPUT属性被设置为1时,构建目录中只会生成目标文件,而不会生成复制文件。这样就避免了多个目标文件输出到同一目录下的冲突问题。

CLEAN_DIRECT_OUTPUT 属性可以防止 CMake 删除其他库文件,是因为该属性告诉 CMake 不要删除其它同名的库文件。CMake 在构建新的 target 时会检查目标文件的输出路径是否已经存在同名的文件,如果存在,则会在构建新的 target 前删除该文件。如果设置了 CLEAN_DIRECT_OUTPUT 属性,则会防止 CMake 删除其他同名文件,从而确保同时生成共享库和静态库,并存储在构建目录的 lib 目录中。


SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

在 CMake 中,使用 SET_TARGET_PROPERTIES 命令可以为目标设置属性。这里设置了 hello 目标的 VERSION 和 SOVERSION 属性。其中,VERSION 属性指定了库的版本号,而 SOVERSION 属性指定了库的 API 版本号。

这两个属性在生成共享库时非常有用。在 Linux 系统中,共享库的命名格式一般为 lib<name>.so.<major>.<minor>.<patch>,其中 <major> 是 API 版本号,<minor> 是库的主要版本号,<patch> 是库的修订版本号。如果库的 API 发生了重大变化,那么就需要修改库的 API 版本号。而库的主要版本号和修订版本号则是用来表示库的功能和修复 bug 的更新。

在设置 VERSION 和 SOVERSION 属性后,生成的共享库文件名将会自动包含版本号信息。例如,如果 VERSION 属性设置为 1.2,SOVERSION 属性设置为 1,那么生成的共享库文件名就会是 libhello.so.1.2.0,其中 .0 是修订版本号。这样,使用方就可以方便地判断库的版本和 API 版本,并且可以同时安装多个版本的库,而不会互相冲突。

其中,VERSION 属性表示库的完整版本号,形式为 major.minor.patch。比如,如果将 VERSION 属性设置为 1.2,则表示库的完整版本号为 1.2.0。

SOVERSION 属性则表示库的 API 版本号,即库的兼容版本号。它的形式为 major,即只包含主版本号。比如,如果将 SOVERSION 属性设置为 1,则表示库的 API 版本号为 1。

在设置了这两个属性之后,CMake 会根据它们生成库文件的名称。具体规则如下:

  • 如果设置了 VERSION 属性,则库文件名为 lib<name>.so.<VERSION>
  • 如果只设置了 SOVERSION 属性,则库文件名为 lib<name>.so.<SOVERSION>.0
  • 如果两个属性都没有设置,则库文件名为 lib<name>.so

因此,如果将 VERSION 属性设置为 1.2,SOVERSION 属性设置为 1,生成的库文件名为 libhello.so.1.2.0。这个库文件的完整版本号为 1.2.0,API 版本号为 1。如果后续只对库进行小改动,比如修复了几个 bug,只需要更新 PATCH 版本号,然后重新编译即可。在这种情况下,生成的库文件名不会变化,因为 API 版本号并没有发生变化。只有当对库进行了不兼容的改动,才需要更新 MAJOR 版本号,同时修改 API,此时生成的库文件名会发生变化。


INSTALL(TARGETS hello hello_static
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)

这段代码是用来安装生成的库文件到系统目录中。其中,INSTALL 命令用于设置安装规则,TARGETS 用于指定要安装的目标,LIBRARY DESTINATION 用于指定共享库文件安装目录,ARCHIVE DESTINATION 用于指定静态库文件安装目录。在本例中,hello 和 hello_static 库将会被安装到系统的 lib 目录下。

在 CMake 的安装指令 INSTALL 中,LIBRARYARCHIVE 都是用来指定要安装的目标类型的。

LIBRARY 用于指定共享库文件类型的目标,通常是使用 ADD_LIBRARY 命令创建的共享库目标。在安装时,CMake 会将共享库文件复制到指定的目录,并且还会自动根据目标的名称生成 .so.so.x 文件,其中 x 表示 SOVERSION 属性指定的版本号。通常将共享库文件安装到系统的 lib 目录或者自定义的目录下。

ARCHIVE 用于指定静态库文件类型的目标,通常是使用 ADD_LIBRARY 命令创建的静态库目标。在安装时,CMake 会将静态库文件复制到指定的目录,并且还会自动根据目标的名称生成 .a 文件。通常将静态库文件安装到系统的 lib 目录或者自定义的目录下。

INSTALL 命令中,还可以使用 RUNTIME 指定可执行文件类型的目标,使用 FILES 指定普通文件类型的目标等。


如果你在 CMakeLists.txt 文件中没有定义 CMAKE_INSTALL_PREFIX 变量,那么运行 cmake -DCMAKE_INSTALL_PREFIX=/user 指令是有用的。在这种情况下,CMake 会使用你在命令行中指定的值来设置安装前缀。

CMAKE_INSTALL_PREFIX 变量用于指定安装目录的根目录。当你运行 make install 命令时,生成的文件将被安装到 CMAKE_INSTALL_PREFIX 指定的目录下。

需要注意的是,在 CMakeLists.txt 文件中定义了 CMAKE_INSTALL_PREFIX 变量时,命令行中指定的值会被忽略。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值