.c 文件到可执行文件的编译过程包括以下几个主要步骤:
预处理:
编译器读取 .c 文件,并处理预处理器指令,如 #include、#define、#ifdef 等。
预处理器将所有的 #include 指令替换为相应的文件内容,并展开所有的宏定义。
预处理后的文件通常以 .i 结尾,例如 main.c 预处理后可能生成 main.i。
编译:
编译器读取预处理后的 .i 文件,并将其转换为汇编代码。
编译器检查代码的语法和语义,生成汇编代码。
编译器还会处理所有的数据声明,如 int、float 等,并生成相应的汇编代码。
编译后的文件通常以 .s 结尾,例如 main.i 编译后可能生成 main.s。
汇编:
汇编器读取编译后的 .s 文件,并将其转换为机器代码。
汇编器将汇编代码转换为机器代码,生成一个机器代码文件。
汇编后的文件通常以 .o 结尾,例如 main.s 汇编后可能生成 main.o。
链接:
链接器读取一个或多个 .o 文件,以及所需的系统库和其他库。
链接器将所有 .o 文件中的机器代码合并成一个单一的文件。
链接器处理所有的符号引用和定义,确保所有的符号都被正确地链接。
链接器生成可执行文件、共享库(.so 文件)或静态库(.a 文件)。
运行时:
生成可执行文件后,操作系统加载该文件到内存中。
程序的入口点(通常是 main 函数)被调用,程序开始执行。
源码:
# Makefile
include .../Arch.make
CC=$(CROSS_COMPILE)gcc
CXX=$(CROSS_COMPILE)g++
AR=$(CROSS_COMPILE)ar
RANLIB=$(CROSS_COMPILE)ranlib
CXXFLAGS = -Wall -pthread -ggdb $(SYSROOT) -I.../include/ -I.../Refsel/ -I.../Alarm/ -I.../drivers/ -I.../Todinput/
LFLAGS = -stdc++ -lgcc_s -L.../Alarm -lss_alarm -L.../Istate -lss_istate -L.../Refsel -lzss_refs -L.../Todinput -lzss_util -l.../lzss_imp
PROGRAMS = impd
all: libzss_imp.so $(PROGRAMS)
$(MAKE) -C test$(@)
lib: libzss_imp.so
impd: card_util.o Input.o InputSpan.o InputEvent.o InputSelect.o SpanProc.o inputEl.o
$(CXX)$(CXXFLAGS) $(LFLAGS) card_util.o Input.o InputSpan.o InputEvent.o InputSelect.o SpanProc.o inputEl.o -o$(@)
inputEl.o: inputEl.pub.h inputEl.priv.h inputEl.cpp
libzss_imp.so: imp_lib.o imp_socket.o bits.o
$(CXX)$(SYSROOT) -shared -o $(@) imp_lib.o imp_socket.o bits.o
imp_socket.o: inputEl.pub.h inputEl.priv.h inputEl.socket.cpp
Input.o: Input.h Input.cpp
InputSpan.o: InputSpan.h InputSpan.cpp
InputEvent.o: InputEvent.h InputEvent.cpp
InputSelect.o: InputSelect.h InputSelect.cpp
card_util.o: Input.h InputEvent.h card_util.cpp
SpanProc.o: SpanProc.h SpanProc.cpp
bits.o: ./SharedLib/bits c
$(CXX)$(CXXFLAGS) -fPIC -c c -o $(@)
CXXFLAGS = -Wall -pthread -ggdb $(SYSROOT) -I.../include/ -I.../Refsel/ -I.../Alarm/ -I.../drivers/ -I.../Todinput/
LFLAGS = -stdc++ -lgcc_s -L.../Alarm -lss_alarm -L.../Istate -lss_istate -L.../Refsel -lzss_refs -L.../Todinput -lzss_util -l.../lzss_imp
CXXFLAGS声明系统中.c和.h文件的位置编译可执行文件的时候遇到#include文件夹的时候会通过这个路径寻找文件,LFLAGS是指定动态库,-L指出后面声明动态库位置. -lzss_inp指出本文件夹下有libzss_inp.so的动态库,-l会自动补充lib和.so前后缀
流程解析:
执行make all 指令后先会执行
all: libzss_imp.so $(PROGRAMS)
意思是要开始生成目标文件libzss_imp.so 和impd可执行文件
impd: card_util.o Input.o InputSpan.o InputEvent.o InputSelect.o SpanProc.o inputEl.o
$(CXX)$(CXXFLAGS) $(LFLAGS) card_util.o Input.o InputSpan.o InputEvent.o InputSelect.o SpanProc.o inputEl.o -o$(@)
生成impd需要指明$(CXXFLAGS) $(LFLAGS)即指定动态库和相关文件的位置
libzss_imp.so: imp_lib.o imp_socket.o bits.o
$(CXX)$(SYSROOT) -shared -o $(@) imp_lib.o imp_socket.o bits.o
生成动态库是将多个.o文件合并成一个可执行文件.so
SpanProc.o: SpanProc.h SpanProc.cpp
bits.o: ./SharedLib/bits c
$(CXX)$(CXXFLAGS) -fPIC -c c -o $(@)
c++ 文件可以简化编译流程,c代码需要指定编译过程