You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:53:15