持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情。
一、源码剖析
更多细节大家可以看原网站
目录结构
我们先构建这个一个文件,名为 hello_shared_lib,其名下
hello.hpp
#pragma once
#include <string>
#include "hello/export_hello.hpp"
namespace hello{
/// Example class that is explicitly exported into a dll
class CH3_HELLO_SHARED_EXPORT Hello {
public:
Hello(const std::string& name) : name_{name} {}
void greet() const;
private:
const std::string name_;
};
}
通过include的内容我们可以看出 export_hello.hpp 并非我们已知的文件,那么他是什么呢?如何生成的呢?我们后面来揭晓。
hello.cpp
#include <hello/hello.hpp>
#include "internal.hpp"
namespace hello{
void Hello::greet() const {
details::print_impl(name_);
}
}
internal.cpp
#include "internal.hpp"
#include <iostream>
namespace hello::details{
void print_impl(const std::string& name)
{
std::cout << "Hello " << name << " from a shared library\n";
}
}
internal.hpp
#pragma once
#include <string>
namespace hello::details{
void print_impl(const std::string& name);
}
CMakeLists.txt
# Chapter3- example illustrating how to create a shared library
# Additionally the example shows how to set a postfix for debug libraries and
# how to handle symbol visibilities for shared libraries
#
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.17)
project(
ch3_hello_shared
VERSION 1.0.0
DESCRIPTION
"A simple C++ project to demonstrate creating executables and libraries in CMake"
LANGUAGES CXX
)
# set the postfix "d" for the resulting .so or .dll files when building the
# library in debug mode
set(CMAKE_DEBUG_POSTFIX
d
)
# add the library target
add_library(ch3_hello_shared SHARED)
# set properties for the target. VERSION set the library version to the project
# version * SOVERSION set the compatibility version for the library to the
# major number of the version
set_target_properties(
ch3_hello_shared
PROPERTIES VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
# add sources to the library target
target_sources(
ch3_hello_shared
PRIVATE src/hello.cpp src/internal.cpp
)
# define the C++ standard needed to compile this library and make it visible to
# dependers
target_compile_features(
ch3_hello_shared
PUBLIC cxx_std_17
)
# set the include directories
target_include_directories(
ch3_hello_shared
PRIVATE src/ch3_hello_shared
PUBLIC include
)
# if using limited visibility, set CXX_VISIBILILTY_PRESET to "hidden"
include(GenerateExportHeader)
set_property(
TARGET ch3_hello_shared
PROPERTY CXX_VISIBILITY_PRESET "hidden"
)
# Hide inlined functions by default, reducing the size of the library
set_property(
TARGET ch3_hello_shared
PROPERTY VISIBILITY_INLINES_HIDDEN TRUE
)
# this command generates a header file in the CMAKE_CURRENT_BINARY_DIR which
# sets the visibility attributes according to the compiler settings
generate_export_header(
ch3_hello_shared
EXPORT_FILE_NAME
export/hello/export_hello.hpp
)
# Add CMAKE_CURRENT_BINARY_DIR to the include path so the generated header can
# be found
target_include_directories(
ch3_hello_shared
PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/export"
)
# An alternative but not recomended way export the symbols is to use
# set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) Which exports all dll symbols by
# default
使用 set 在构建 .so 或 .dll 文件时,为结果(CMAKE_DEBUG_POSTFIX)设置后缀“d”。
使用add_librar 为添加库目标,SHARED 添加的库为共享库。
将CMAKE_CURRENT_BINARY_DIR添加到包含路径,以便生成的头文件可以被发现。
二、原理梳理
为了更清晰的理解编译过程,从源文件到可执行文件究竟发生了什么?我们来看几个问题。
1.CPU 可以解析和运行的程序形式称为什么代码?
本地代码(机器语言代码)
2.将多个目标文件结合生成 EXE 文件的工具称为什么?
链接器
通过编译和链接,得到 EXE 文件。
3.扩展名为 .obj的目标文件的内容,是源代码还是本地代码?
本地代码
通过对源文件进行编译,得到目标文件。例如,C 语言中,将 Sample1.c 这个源文件编译后,就会得到 Sample1.obj 这个目标文件。目标文件的内容是本地代码。
4.把多个目标文件收录在一起的文件称为什么?
库文件
链接器会从库文件中抽取出必要的目标文件并将其结合到 EXE 文件中。此外,还存在一种程序运行时结合的 DLL 形式的库文件。
5.仅包含 Windows的DLL 文件中存储的函数信息的文件称为什么?
导入库
把导入库信息结合到 EXE 文件中,这样程序在运行时就可以利用 DLL 内的函数了。
6.在程序运行时,用来动态申请分配的数据和对象的内存区域形式称为什么?
堆
堆的内存空间会根据程序的命令进行申请及释放。