如何处理Linux与Windows间共享库文件名扩展名差异?
处理跨平台共享库扩展名差异的最佳实践?
背景
我正在开发一个同时面向Linux和Windows的项目,原项目使用手写Makefile构建,因此在两个平台上生成的共享库均为.so扩展名。迁移到CMake构建后,Linux平台仍生成.so扩展名的共享库,但Windows平台生成的是.dll扩展名。由于代码中硬编码使用dlopen()延迟加载.so扩展名的共享库,导致应用在Windows运行时失败。
测试发现,将生成的.dll文件重命名为.so后,应用可正常运行,因此动态链接库与共享库的底层差异不影响当前需求。
核心问题
是否存在标准或最佳实践来处理Linux与Windows间共享库文件名扩展名的差异?我能想到基于宏的解决方案,例如:
#ifdef SOMETHING #define EXTENSION ".so" #else #define EXTENSION ".dll" #endif ... void* handle = dlopen("libfunc" EXTENSION, RTLD_NOW);
但我想了解是否有广泛采用的最佳实践、通用惯例或更规范的处理方式。本质需求是在Windows平台加载.dll扩展名的文件,在Linux平台加载.so扩展名的文件。
(注:我认为手写Makefile在所有平台生成.so文件是出于经验不足或便利性,而CMake在Linux生成.so、Windows生成.dll是更符合平台规范的做法,因此需要在代码中为dlopen()加载的共享库扩展名添加编译时或运行时条件判断)
最小可编译示例资源
main.c
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { int (*fptr)(void) = NULL; const char* filename = "libfunc.so"; // 注意这里硬编码了扩展名 void* handle = dlopen(filename, RTLD_NOW); if (! handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } fptr = dlsym(handle, "func"); fprintf(stdout, "fptr returns %d\n", (*fptr)()); dlclose(handle); return 0; }
dlfcn.h(Windows下模拟dlopen接口)
#ifndef DLFCN_H #define DLFCN_H #include <windows.h> #define RTLD_NOW (1<<0) extern inline void *dlopen(const char *lib, int flags) { (void) flags; return LoadLibraryExA(lib, NULL, 0); } extern inline void *dlsym(void *handle, const char *name) { FARPROC fp = GetProcAddress((HINSTANCE) handle, name); return (void *)(intptr_t)fp; } extern inline char *dlerror() { // 非线程安全! static char msg[1024]; msg[0] = '\0'; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, msg, sizeof(msg), NULL); return msg; } extern inline int dlclose(void *handle) { return FreeLibrary(handle) ? 0 : -1; } #endif
func.c
int func(void) { return 42; }
Makefile
.PHONY: all CFLAGS := ifeq ($(shell uname), Windows_NT) CFLAGS += -isystem . endif all: libfunc.so a.out libfunc.so: func.o cc -shared -fpic -o $@ $^ a.out: libfunc.so main.c cc -o $@ main.c ${CFLAGS}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(hello_world) add_library(func SHARED func.c) add_executable(a.out main.c) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}) endif()
测试结果
Linux下使用make编译运行
$ make cc -c -o func.o func.c cc -shared -fpic -o libfunc.so func.o cc -o a.out main.c $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./a.out fptr returns 42 $
Linux下使用cmake编译运行
$ cmake -B build && cmake --build build -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting C compile features -- Detecting C compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/user/dev/shared-lib-test/build [ 25%] Building C object CMakeFiles/func.dir/func.c.o [ 50%] Linking C shared library libfunc.so [ 50%] Built target func [ 75%] Building C object CMakeFiles/a.out.dir/main.c.o [100%] Linking C executable a.out [100%] Built target a.out $ $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/build ./build/a.out fptr returns 42 $
Windows(w64devkit环境)下使用make编译运行
$ make cc -isystem . -c -o func.o func.c cc -shared -fpic -o libfunc.so func.o cc -o a.out main.c -isystem . $ $ ./a.out fptr returns 42 $
Windows(w64devkit环境)下使用cmake编译运行
$ cmake -G "Unix Makefiles" -B build && cmake --build build -- The C compiler identification is GNU 13.2.0 -- The CXX compiler identification is GNU 13.2.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: C:/Program Files/w64devkit/bin/cc.exe - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: C:/Program Files/w64devkit/bin/c++.exe - skipped -- Detecting C compile features -- Detecting C compile features - done -- Configuring done (3.1s) -- Generating done (0.1s) -- Build files have been written to: C:/Users/user/dev/shared-lib-test/build [ 25%] Building C object CMakeFiles/func.dir/func.c.obj [ 50%] Linking C shared library libfunc.dll [ 50%] Built target func [ 75%] Building C object CMakeFiles/a.out.dir/main.c.obj [100%] Linking C executable a.out.exe [100%] Built target a.out $ $ ./build/a.out.exe The specified module could not be found. $ mv ./build/libfunc.dll ./build/libfunc.so $ $ ./build/a.out.exe fptr returns 42 $
内容的提问来源于stack exchange,提问作者StoneThrow
相关产品推荐
相关产品推荐

