linux 编译 c或cpp 文件为动态库 so 文件(最简单直观的模板)

把源码编译打包为动态库so文件,做平台的可能对这些不熟悉。

对我们这些算是经常用到的。

总结个模板,一看就懂的那种,提供给有需要的人。

前提条件,机器上有 gcc工具链。

如果文件个数少,可以直接单个编译,如下:

Building shared lib...
g++ -c -fPIC  Quote.cpp -o  Quote.o
g++ -c -fPIC  QuoteExport.cpp -o  QuoteExport.o
g++ -c -fPIC  Start.cpp -o  Start.o
Generating shared lib...
g++ -shared -fPIC -o  libQuoteLib.so  ./Quote.o  ./QuoteExport.o  ./Start.o  
cp libQuoteLib.so ../
OK!
 

如果文件个数较多,或者夸文件夹了,层层嵌套。

那么就整个makefile模板文件,放到代码的根目录下,直接执行一个make即可。

模板文件如下:

############################################################################
#makefile,created by yangyongzhen qq:534117529
############################################################################

#****************************************************************************
# Cross complie path
#****************************************************************************
#GCC_PATH=D:\msysgit\mingw

CROSS_COMPILE=


CC     := $(CROSS_COMPILE)gcc
CXX    := $(CROSS_COMPILE)g++
AS	   := $(CROSS_COMPILE)as
AR     := $(CROSS_COMPILE)ar 
LD     := $(CROSS_COMPILE)ld
RANLIB := $(CROSS_COMPILE)ranlib
OBJDUMP:= $(CROSS_COMPILE)objdump
OBJCOPY:= $(CROSS_COMPILE)objcopy
STRIP  := $(CROSS_COMPILE)strip

#****************************************************************************
# Flags
#****************************************************************************

CFLAGS= 
LDSCRIPT= 
LDFLAGS= 


#****************************************************************************
# Source files
#****************************************************************************
SRC_C=$(shell find . -name "*.cpp")

OBJ_C=$(patsubst %.cpp, %.o, $(SRC_C))

SRCS := $(SRC_C) $(SRC_C)

OBJS := $(OBJ_C) 


#****************************************************************************
# Targets of the build
#****************************************************************************
TARGET   	:= libQuoteLib

.PHONY: clean
all:  prebuild  $(TARGET).so

#****************************************************************************
# TARGET
#****************************************************************************
prebuild:
	@echo Building shared lib...

$(TARGET).so : $(OBJS)
	@echo Generating shared lib...
	$(CXX) -shared -fPIC -o  $(TARGET).so $(OBJS) 
	cp $(TARGET).so ../
	@echo OK!

%.o : %.cpp
	$(CXX) -c -fPIC $(CFLAGS) $< -o  $@
	
clean:
	@echo The following files:
	rm  -f  $(TARGET) *.so
	find . -name "*.[od]" |xargs rm
	@echo Removed!

注:在linux上,源文件的函数或方法前,不需要声明 __declspec(dllexport)
在WIn32上才需要。

所以在头文件中一般会看到:

#ifdef _WIN32
#define TAP_CDECL  __cdecl
#define TAP_DLLEXPORT __declspec(dllexport)
#else
#define TAP_CDECL
#define TAP_DLLEXPORT
#endif

__cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。

被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。

_stdcall 是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。

C中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C++也一样,但是默认的调用方式可以在IDE环境中设置。

带有可变参数的函数必须且只能使用_cdecl方式

__cdecl __fastcall与__stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以及产生函数修饰名的方法。

1、__stdcall调用约定:函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈。

2、__cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。注意:对于可变参数的成员函数,始终使用__cdecl的转换方式。

3、__fastcall调用约定:它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。

4、thiscall仅仅应用于"C++"成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

5、nakedcall采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked call不产生这样的代码。naked call不是类型修饰符,故必须和_declspec共同使用。

关于__declspec的解释,转自:优快云博主「fengbingchun」

原文链接:https://blog.youkuaiyun.com/fengbingchun/article/details/78825004

__declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应该出现在声明的前面。

__declspec(dllexport)用于Windows中的动态库中,声明导出函数、类、对象等供外面调用,省略给出.def文件。即将函数、类等声明为导出函数,供其它程序调用,作为动态库的对外接口函数、类等。

.def文件(模块定义文件)是包含一个或多个描述各种DLL属性的Module语句的文本文件。.def文件或__declspec(dllexport)都是将公共符号导入到应用程序或从DLL导出函数。如果不提供__declspec(dllexport)导出DLL函数,则DLL需要提供.def文件。

__declspec(dllimport)用于Windows中,从别的动态库中声明导入函数、类、对象等供本动态库或exe文件使用。当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。

不使用__declspec(dllimport)也能正确编译代码,但使用__declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。声明一个导入函数,是说这个函数是从别的DLL导入。一般用于使用某个DLL的exe中。
--------------------- 

<think>我们正在处理一个关于在Windows上使用MinGW编译C++代码以生成Linux共享库(.so文件)的问题。根据用户的问题和提供的引用,我们需要指导用户完成这一过程。然而,需要注意的是,MinGW(Minimalist GNU for Windows)是一个用于Windows的GNU工具链,它生成的是Windows本地的可执行文件和库(如.dll文件)。要生成Linux的共享库(.so文件),我们需要一个能够在Windows上运行但目标为Linux的交叉编译器。 因此,我们需要设置一个针对Linux的交叉编译环境。这通常意味着我们需要在Windows上安装一个Linux交叉编译工具链。一种常见的方法是使用MinGW-w64来构建一个交叉编译器,者使用现成的工具链(如来自Linux发行版的工具链)但运行在Windows上。然而,更简单的方法是使用Windows Subsystem for Linux (WSL) 者使用一个预先构建好的交叉编译器工具链(例如,使用MinGW-w64构建的x86_64-linux-gnu工具链)。 但是,根据引用[1]和引用[3],用户似乎已经安装了MinGW-w64(用于Windows的GNU编译器)。然而,标准的MinGW-w64编译器只能生成Windows目标文件,不能生成Linux目标文件。因此,我们需要一个针对Linux的交叉编译器。 步骤概述: 1. 获取一个针对Linux的交叉编译工具链(例如,x86_64-linux-gnu-g++)。 2. 在Windows上安装该工具链。 3. 使用该工具链编译C++代码,指定目标为Linux共享库。 由于在Windows上直接获取Linux交叉编译器并不常见,我们可能需要通过WSL(推荐)者使用Cygwin/MinGW-w64来构建交叉编译器。但是,对于大多数用户,使用WSL可能是最简单的方法。 然而,如果用户坚持要在纯Windows环境下(不使用WSL)进行交叉编译,我们可以尝试以下方法: ### 方法1:使用MinGW-w64构建交叉编译器(复杂) - 从MinGW-w64构建一个针对Linux的交叉编译器。这需要下载Linux文件和库,并构建整个工具链。这个过程很复杂,通常不推荐普通用户尝试。 ### 方法2:使用现成的交叉编译器工具链(推荐) - 我们可以下载一个预编译的交叉编译器工具链。例如,用于Windows的Linaro GCC工具链(针对ARM Linux者x86_64-w64-mingw32和x86_64-linux-gnu工具链。但是,对于x86_64 Linux,我们可以尝试以下步骤: 1. 下载针对Windows的x86_64-linux-gnu交叉编译器。例如,从Ubuntu的官方仓库中获取,但需要Windows版本。我们可以使用MSYS2环境来安装交叉编译器。 2. 安装MSYS2(一个提供类似Linux环境的Windows系统),然后在MSYS2中安装交叉编译器。 ### 方法3:使用Docker(推荐) - 使用Docker for Windows,然后在容器中编译生成Linux共享库。这种方法简单且可靠。 ### 方法4:使用WSL(Windows Subsystem for Linux) - 在Windows 10/11上启用WSL,安装一个Linux发行版(如Ubuntu),然后在其中安装g++,编译生成.so文件。 由于用户明确提到使用MinGW,我们可能更关注方法2。但是,在Windows上使用MinGW-w64生成Linux目标文件并不是MinGW-w64的主要用途。因此,我们将重点放在使用MSYS2来安装交叉编译器。 ## 具体步骤(使用MSYS2安装交叉编译器) 1. **安装MSYS2** - 从官网下载并安装MSYS2:https://www.msys2.org/ - 按照说明更新基本包。 2. **安装针对Linux的交叉编译器** - 打开MSYS2的MINGW64 shell(注意:不是MSYS2 shell,因为MINGW64 shell提供了MinGW-w64工具链)。 - 安装交叉编译器工具链。对于64位Linux,我们可以安装`mingw-w64-x86_64-linux-gcc`(注意:这个包名可能不准确,因为MSYS2的包名可能会变)。实际上,在MSYS2中,针对Linux的交叉编译器包可能是`mingw-w64-x86_64-linux-gcc`,但更常见的是使用`x86_64-linux-gnu-gcc`。然而,MSYS2提供了`mingw-w64-cross`工具链,但主要是针对其他Windows架构的交叉编译。对于Linux目标,我们需要的是`mingw-w64-x86_64-linux-gnu-gcc`。 经过查询,在MSYS2中,我们可以通过以下命令安装针对64位Linux的交叉编译器: ``` pacman -S mingw-w64-x86_64-linux-gnu-gcc ``` 但是,请注意,这个包可能不在默认仓库中,者包名可能不同。实际上,MSYS2目前并没有提供官方的针对Linux的交叉编译器。因此,这种方法可能行不通。 ## 替代方案:使用预构建的交叉编译器 我们可以从第三方获取预构建的交叉编译器,例如从Sourcery Tools(以前是CodeSourcery)者从Linaro。但是,这些通常针对ARM架构。对于x86_64 Linux,我们可以尝试从以下链接获取: - https://toolchains.bootlin.com/ 提供了多种架构的交叉编译器,包括x86_64,但是它们是为Linux主机设计的,不能在Windows上直接运行。 ## 结论:推荐使用WSLDocker 由于在纯Windows环境下设置交叉编译环境较为复杂,我们推荐用户使用以下两种方法之一: ### 使用WSL(推荐) 1. 启用WSL:以管理员身份打开PowerShell并运行: ```powershell wsl --install ``` 然后重启计算机。默认会安装Ubuntu。 2. 在WSL中安装g++: ```bash sudo apt update sudo apt install g++ ``` 3. 编写代码并在WSL中编译: ```bash g++ -shared -fPIC -o mylib.so mylib.cpp ``` ### 使用Docker 1. 安装Docker Desktop for Windows。 2. 创建一个Dockerfile,使用一个包含g++的Linux镜像(如gcc)。 3. 运行容器并挂载源代码目录,然后在容器内编译。 ## 如果用户坚持使用MinGW生成Linux库 如果用户必须在纯Windows环境下使用MinGW风格的交叉编译器,我们可以尝试使用MXE(M cross environment)。MXE是一个用于在类Unix系统上交叉编译Windows程序的工具,但它也支持在Linux上构建交叉编译器。然而,MXE也可以在MSYS2环境中使用,但步骤较为复杂。 由于时间和复杂性的原因,我们可能建议用户考虑使用WSLDocker。 ## 回答用户 根据以上分析,我们给出以下回答: --- 在Windows操作系统上,使用MinGW(Minimalist GNU for Windows)编译生成Linux共享对象(.so文件,通常需要交叉编译器。MinGW本身设计用于生成Windows原生二进制文件(如.exe和.dll),而非Linux的.so文件。因此,我们需要设置一个针对Linux的交叉编译环境。以下是几种可行的方法: ### 方法一:使用Windows Subsystem for Linux (WSL)(推荐) 1. **启用WSL**:在管理员权限的PowerShell中执行: ```powershell wsl --install ``` 安装完成后重启计算机。默认将安装Ubuntu发行版[^1]。 2. **安装G++编译器**:在WSL终端中运行: ```bash sudo apt update sudo apt install g++ ``` 3. **编译共享库**:进入源代码目录,使用以下命令编译: ```bash g++ -shared -fPIC -o mylib.so mylib.cpp ``` 生成的`mylib.so`即为Linux共享库。 ### 方法二:使用Docker容器 1. **安装Docker Desktop for Windows**:从[Docker官网](https://www.docker.com/products/docker-desktop)下载并安装。 2. **创建Dockerfile**(可选):如果项目需要自定义构建环境,可创建Dockerfile,例如: ```dockerfile FROM gcc:latest WORKDIR /usr/src/myapp COPY . . RUN g++ -shared -fPIC -o mylib.so mylib.cpp ``` 3. **编译共享库**:在项目目录中运行以下命令,使用Docker容器编译: ```bash docker run --rm -v "%cd%":/usr/src/myapp -w /usr/src/myapp gcc g++ -shared -fPIC -o mylib.so mylib.cpp ``` 此命令将当前目录挂载到容器中,并在容器内执行编译命令。 ### 方法三:使用交叉编译器(高级) 若必须在纯Windows环境下编译,需安装针对Linux的交叉编译器(如`x86_64-linux-gnu-g++`)。但此类工具链在Windows上较难直接获取,建议通过以下步骤尝试: 1. **安装MSYS2**:从[MSYS2官网](https://www.msys2.org/)下载安装。 2. **在MSYS2中安装交叉编译器**(如可用): 打开MSYS2 MINGW64终端,尝试安装: ```bash pacman -S mingw-w64-x86_64-linux-gnu-gcc ``` **注意**:此包可能不存在名称不同。若不可用,需手动构建寻找第三方预编译工具链,过程较为复杂。 3. **编译共享库**:若安装成功,使用以下命令编译: ```bash x86_64-linux-gnu-g++ -shared -fPIC -o mylib.so mylib.cpp ``` ### 总结 - **推荐方法**:使用WSLDocker,步骤简单且环境与Linux原生一致。 - **备选方案**:若需纯Windows环境,可尝试MSYS2交叉编译器,但需自行解决工具链获取问题。 - **注意事项**:编译后的.so文件只能在Linux系统使用,无法在Windows直接运行。 §§相关问题§§ 1. 如何在Windows上安装和配置WSL? 2. Docker容器编译与本地编译有何区别? 3. 交叉编译器的工作原理是什么? 4. 如何验证生成的.so文件是否兼容目标Linux系统? [^1]: [MinGW-w64下载地址](https://sourceforge.net/projects/mingw-w64/) [^2]: 关于getopt.h在Windows的兼容性问题,参考Stack Overflow讨论 [^3]: OpenCV编译示例中的MinGW使用 [^4]: Qt与OpenCV在Windows的配置教程</think>### 如何在 Windows 上使用 MinGW 编译 C++ 代码生成 Linux .so 文件 在 Windows 上使用 MinGW 编译生成 Linux 共享库(.so 文件)需要**交叉编译器**的支持。以下是详细步骤: --- #### 1. **安装 MinGW-w64 交叉编译器** - 下载 Linux 目标平台的交叉编译工具链(例如 `x86_64-linux-gnu`): ```bash pacman -S mingw-w64-x86_64-linux-gnu-gcc ``` 在 MSYS2 终端中执行此命令(需先[安装 MSYS2](https://www.msys2.org/))[^1]。 - 验证安装: ```bash x86_64-linux-gnu-gcc --version ``` 应显示针对 LinuxGCC 版本信息。 --- #### 2. **编写 C++ 代码示例** 创建文件 `mylib.cpp`: ```cpp #include <iostream> extern "C" { void hello() { std::cout << "Hello from Linux .so!" << std::endl; } } ``` --- #### 3. **编译生成 Linux .so 文件** 使用交叉编译器命令: ```bash x86_64-linux-gnu-g++ -shared -fPIC -o mylib.so mylib.cpp ``` - **`-shared`**:生成共享库 - **`-fPIC`**:生成位置无关代码(Linux 共享库必需) --- #### 4. **验证 .so 文件兼容性** 在 Linux 系统中检查: ```bash file mylib.so # 应显示 "ELF 64-bit LSB shared object, x86-64" ldd mylib.so # 检查动态链接库依赖 ``` --- #### 注意事项 1. **环境限制**: - MinGW 原生编译生成的是 Windows 的 `.dll` 文件[^2]。 - 交叉编译的 `.so` 文件**只能在 Linux 运行**,无法直接在 Windows 使用。 2. **依赖处理**: - 若代码依赖 Linux 特有头文件(如 `<sys/epoll.h>`),需在 Windows 提供兼容头文件通过 WSL 编译。 3. **替代方案推荐**: - **WSL**:在 Windows 启用 WSL,直接使用 Linux 的 `g++` 编译(推荐)[^3]。 - **Docker**:使用 Linux 容器编译: ```bash docker run --rm -v %cd%:/src gcc g++ -shared -fPIC -o /src/mylib.so /src/mylib.cpp ``` --- #### 常见问题解决 - **错误:`linux/stddef.h: No such file`** 安装缺失的 Linux文件包: ```bash pacman -S mingw-w64-x86_64-linux-gnu-gcc-libs ``` - **错误:`undefined reference to 'std::cout'`** 显式链接 C++ 标准库: ```bash x86_64-linux-gnu-g++ -shared -fPIC -o mylib.so mylib.cpp -lstdc++ ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

特立独行的猫a

您的鼓励是我的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值