C++数据结构1——可执行文件生成过程
C源代码生成最终可执行文件的过程通常分为四个核心步骤预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。我们可以通过一个经典的HelloWorld程序来完整演示这个过程// hello.cpp #include iostream #define GREETING Hello, World! int main() { std::cout GREETING std::endl; return 0; }在 Linux 系统中使用g编译器整个流程可以通过一条命令完成g hello.cpp -o hello▲g编译器根本任务是将人类可读的 C 源代码.cpp文件转换成计算机可以执行的机器码最终生成可执行文件。但实际上这条命令背后隐藏了以下四个独立的步骤。1. 预处理 (Preprocessing)输入源代码文件 (.cpp)。工具预处理器 (cpp)。主要任务处理所有以#开头的预处理指令。头文件包含 (#include)将iostream等头文件的内容完整地复制到当前文件中。宏展开 (#define)将代码中的GREETING替换为Hello, World!。条件编译 (#ifdef,#ifndef)处理条件编译指令。输出一个纯粹的、可读的翻译单元通常以.i或.ii为扩展名。这个文件里已经没有了任何宏定义或#include指令。实际操作g -E hello.cpp -o hello.i查看hello.i文件你会发现它的末尾部分变成了这样// 前面是 iostream 展开的上千行代码 ... int main() { std::cout Hello, World! std::endl; return 0; }可以看到#include iostream被替换成了上千行代码而GREETING被直接替换成了字符串字面量。2. 编译 (Compilation)输入预处理后的文件 (.i或.ii)。工具编译器核心 (cc1plus)。主要任务这是最核心、最复杂的一步。它将高级语言代码翻译成汇编语言。词法分析、语法分析、语义分析检查代码是否符合语言规范。优化进行各种优化如删除无用代码、内联函数等。生成汇编代码产生针对目标CPU架构如x86-64, ARM的汇编指令。输出一个汇编语言文件通常以.s为扩展名。实际操作g -S hello.i -o hello.s3. 汇编 (Assembly)输入汇编语言文件 (.s)。工具汇编器 (as)。主要任务将人类可读的汇编指令翻译成机器可执行的机器码。输出一个目标文件 (Object File)通常以.o(Linux/macOS) 或.obj(Windows) 为扩展名。这个文件里包含了二进制机器码但它还不是一个可执行程序因为其中的地址和外部符号如std::cout尚未被解析。实际操作g -c hello.s -o hello.o # 或者直接从源代码生成 .o 文件 # g -c hello.cpp -o hello.o可以使用nm命令查看目标文件中的符号nm hello.o输出中会有一个U _ZSt4cout这代表std::cout是一个未定义 (Undefined)的外部符号它将在链接步骤中被解析。4. 链接 (Linking)输入一个或多个目标文件(.o/.obj) 和库文件(.a/.lib/.so/.dll)。工具链接器 (ld或lld)。主要任务将所有的目标文件和库文件“组装”在一起解决它们之间的符号引用问题。符号解析将hello.o中对std::cout的引用与 C 标准库中std::cout的实际定义地址关联起来。重定位为代码和数据分配最终的内存地址修正所有指令中的地址。合并段将所有输入文件的代码段 (.text)、数据段 (.data) 等合并到输出文件中。输出最终的可执行文件 (Linux/macOS 下无扩展名Windows下为.exe) 或共享库文件 (.so/.dll)。实际操作g hello.o -o hello———————————————————————————————————————————· 另一种思路——CMakeCMake是跨平台的构建系统生成器不直接编译代码与g不同而是用一种更高级、更抽象的配置文件CMakeLists.txt来描述项目然后自动为你生成对应平台的原生构建文件比如 Linux 下的 Makefile 或 Windows 下的 Visual Studio 项目文件。示例# CMakeLists.txt cmake_minimum_required(VERSION 3.10) # 1. 编译器设置 set(CMAKE_CUDA_COMPILER /usr/local/cuda/bin/nvcc) project(RadarISAC LANGUAGES CXX CUDA) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CUDA_STANDARD 14) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # 2. 查找库 find_package(Qt5 COMPONENTS Core Gui Widgets PrintSupport REQUIRED) find_package(CUDA REQUIRED) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/processing ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty /usr/local/cuda/include ) # 模块 A: CUDA 核心静态库 (公用部分) set(CUDA_SOURCES processing/cuda_algo.cu processing/cuda_algo.h ) add_library(RadarCudaLib STATIC ${CUDA_SOURCES}) set_property(TARGET RadarCudaLib PROPERTY CUDA_ARCHITECTURES 87) target_link_libraries(RadarCudaLib PRIVATE ${CUDA_CUFFT_LIBRARIES}) set_property(TARGET RadarCudaLib PROPERTY POSITION_INDEPENDENT_CODE ON) # 模块 B: 原始 GUI 程序 (自己调试) set(GUI_SOURCES main.cpp mainwindow.cpp mainwindow.h processing/radar_processor.cpp processing/radar_processor.h 3rdparty/qcustomplot.cpp 3rdparty/qcustomplot.h ) add_executable(RadarGUI ${GUI_SOURCES}) target_link_libraries(RadarGUI PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::PrintSupport RadarCudaLib ${CUDA_LIBRARIES} ) # 模块 C: 共享库 .so (Python 调用) set(LIB_SOURCES radar_interface.cpp processing/radar_processor.cpp processing/radar_processor.h ) # 生成动态库 (SHARED) add_library(RadarLib SHARED ${LIB_SOURCES}) # 设置输出名字为 RadarISAC - 最终生成 libRadarISAC.so set_target_properties(RadarLib PROPERTIES OUTPUT_NAME RadarISAC) # 链接依赖 (注意这里链接了开启 PIC 的 RadarCudaLib) target_link_libraries(RadarLib PRIVATE RadarCudaLib ${CUDA_LIBRARIES} cufft )
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2421877.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!