转载:CMake I 编译静态库、动态库和对象库(http://t.csdn.cn/iEf7a)

目录

一、源文件

1.Message.h

2.Message.cpp

3.helloworld.cpp

二、CMakeLists.txt

1.源文件

2.CMake语言说明

(1)cmake_minimum_required

(2)project

(3)add_library

(4)add_executable

(5)target_link_libraries

三、cmake配置及编译

1.cmake配置

2.构建/编译

【扩展】编译动态库

(1)修改CMakeLists.txt

(2)进行配置及构建

【扩展】编译对象库

(1)修改CMakeLists.txt

(2)构建及编译

(3)修改库名称


        上一篇入门文章只有一个文件,今天搞稍微复杂一点,增加一个类Message,将其编译为一个静态库或动态库。

一、源文件

1.Message.h

 
查看代码
查看代码
 #pragma once
#include <iosfwd>
#include <string>
 
class Message
{
private:
	std::string _message;
	std::ostream& printObject(std::ostream& os);
 
public:
	Message(const std::string& m) :_message(m)
	{
	}
	friend std::ostream& operator<<(std::ostream& os, Message& obj)
	{
		return obj.printObject(os);
	}
};

2.Message.cpp

查看代码
查看代码
 #include "Message.h"
#include <iostream>
#include <string>
std::ostream &Message::printObject(std::ostream &os)
{
	os<<"This is message:"<<std::endl;
	os<<_message;
	return os;
}

 

3.helloworld.cpp

查看代码
 #include "Message.h"
#include <iostream>
#include <string>
 
int main()
{
	Message sayHello("Hello C++");
	std::cout<<sayHello<<std::endl;
 
	Message sayBye("Bye C++");
	std::cout<<sayBye<<std::endl;
	
	return EXIT_SUCCESS;
}

二、CMakeLists.txt

1.源文件

查看代码
 cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(buildLib LANGUAGES CXX)
 
#生成必要的构建指令,将指定的源码编译到库中。
add_library(message 
	STATIC
	Message.cpp
	Message.h
	)
 
add_executable(helloworldexe helloworld.cpp)
#将库链接到可执行文件。
target_link_libraries(helloworldexe message)

2.CMake语言说明

(1)cmake_minimum_required

        设置CMake所需的最低版本。如果使用的CMake版本低于该版本,则会发出致命错误。

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

(2)project

        声明了项目的名称(buildLib)和支持的编程语言(CXX代表C++)。

project(buildLib LANGUAGES CXX)

(3)add_library

        创建目标——静态库。库的名称(message)和源码文件名相同。

add_library(message STATIC Message.cpp Message.h)

        CMake接受其他值作为 add_library 的第二个参数的有效值:

  • STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
  • SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。
  • OBJECT:用于创建对象库,可将给定 add_library 的列表中的源码编译到目标文件,不将它们归档到静态库中, 也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。
  • MODULE:又为DSO组。与 SHARED 库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。 

        CMake还能够生成特殊类型的库,这不会在构建系统中产生输出,但是对于组织目标之间的依赖关系, 和构建需求非常有用:

  • IMPORTED:此类库目标表示位于项目外部的库。此类库的主要用途是,对现有依赖项进行构建。 因此, IMPORTED 库将被视为不可变的。我们将在本书的其他章节演示使用 IMPORTED 库的示例。
  • INTERFACE:与 IMPORTED 库类似。不过,该类型库可变,没有位置信息。它主要用于项目之外的目标构建使用。我们将在本章第5节中演示 INTERFACE 库的示例。
  • ALIAS:顾名思义,这种库为项目中已存在的库目标定义别名。不过,不能为 IMPORTED 库选择别名。

(4)add_executable

        指示CMake创建一个新目标:可执行文件(helloworldexe)。

add_executable(helloworldexe helloworld.cpp)

        将目标库(message)链接到可执行目标(helloworldexe)。

target_link_libraries(helloworldexe message)

三、cmake配置及编译

1.cmake配置

        使用cmake ..来进行配置,生成buildLib.sln项目:

2.构建/编译

        使用cmake --build . 来进行构建,生成静态库及可执行文件:

 【扩展】编译动态库

        在 Windows 平台中生成动态库的源码和静态库是不同的。

        在 Windows 平台中,我们导出动态库时,除了会生成 .dll 动态库之外还会生成一个 .lib 文件。这个 .lib 文件和静态库的 .lib 文件不同,它里面并不保存代码生成的二进制文件,而是所有需要导出符号的符号表。因此这个 .lib 文件和编译静态库生成的 .lib 文件相比会小很多。

        这个导出的符号表是需要我们在源码中进行指定的。如果我们希望将将一个符号(symbol)导出(这里的符号可以指类、函数等各种类型):

  • 方法一:需要在其前面加上 __declspec(dllexport) 标志。这样这个符号的相关信息就会导出的 .lib 中的符号表中了。
  • 方法二:在CMakeLists.txt里添加set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

        如果我们的源码中没有任何 __declspec(dllexport) ,并且没有在CMakeLists.txt里设置"导出所有符号"的话,我们依然可以成功的编译出动态库,但是并不会生成保存符号表的.lib 文件。这也是在 Windows 平台下编译动态库经常出现的问题。

(1)修改CMakeLists.txt

  1.  
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
  2.  
    add_library(message SHARED Message.cpp Message.h)

(2)进行配置及构建

 【扩展】编译对象库

(1)修改CMakeLists.txt

查看代码
 cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
 
project(buildLib LANGUAGES CXX)
 
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
 
add_library(message-objs
	OBJECT
	Message.cpp
	Message.h
	)
	
set_target_properties(message-objs
	PROPERTIES
	POSITION_INDEPENDENT_CODE 1
	)
#获取动态库
add_library(message-shared
	SHARED 
	$<TARGET_OBJECTS:message-objs>
)
#获取静态库
add_library(message-static
	STATIC
	$<TARGET_OBJECTS:message-objs>
	)
	
add_executable(helloworldexe helloworld.cpp)
 
target_link_libraries(helloworldexe message-static)

1.需要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令,设 置 message-objs 目标的相应属性来实现。(可能在某些平台和/或使用较老的编译器上,需要显式地为目标设置 POSITION_INDEPENDENT_CODE 属性。

2.引用对象库的生成器表达式语法: $<TARGET_OBJECTS:message-objs>

(2)构建及编译

(3)修改库名称

查看代码
 #修改动态库名称
set_target_properties(message-shared
	PROPERTIES
	OUTPUT_NAME "shared-message"
	)
 
#修改静态库名称
set_target_properties(message-static
	PROPERTIES
	OUTPUT_NAME "static-message"
	)

 

 
posted @ 2022-12-14 09:57  小超不挑食  阅读(381)  评论(0编辑  收藏  举报