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

Windows下CMake打包C/C++库供调用的错误排查与规范优化

背景

我用CMake在Windows平台给C/C++程序调用共享或静态库,总结了两步入门流程,但遇到了问题:

  • 在Ubuntu(WSL)环境下用g++编译完全正常;
  • 在Windows环境下用Visual Studio 2022打开项目,通过开发者PowerShell编译失败。

问题

  1. 执行测试步骤后出现链接错误,该怎么修改CMakeLists.txt解决这个Windows平台的错误?
    错误信息:
\CreateSharedLibs\UseLib..\CreateLib\build\lib\MathFunctions.dll : fatal error LNK1107: invalid or corrupt file: cannot read at 0x340
  1. 有没有必要对CMakeLists.txt做额外修改来更符合规范、避免错误?比如要不要用find_library,如果用的话该怎么操作?

测试步骤

先在CreateLib目录执行构建流程,再在UseLib目录执行相同操作:

  • Linux环境下直接在终端执行;
  • Windows环境下可以在Visual Studio中打开目录,用开发者PowerShell执行以下命令:
mkdir build
cd build
cmake ..
cmake --build .

代码结构

CreateLib
   - CMakeLists.txt
   - src
      - MathFunctions.cpp
   - include
      - MathFunctions.h
UseLib
   - CMakeLists.txt
   - src
      - main.cpp

CreateLib 代码文件

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

project(MathFunctionsProject)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

# Set the output directory for the DLL
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# Add the include directory
include_directories(include)

# Define location of source files
set(SOURCE_FILES src/MathFunctions.cpp)

# Create the shared library
add_library(MathFunctions SHARED ${SOURCE_FILES})

# Set the name and properties of the shared library
set_target_properties(MathFunctions PROPERTIES OUTPUT_NAME "MathFunctions" PREFIX "")

# Copy the DLL to the output directory
add_custom_command(TARGET MathFunctions POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:MathFunctions> ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
)

MathFunctions.h

#ifndef MATHFUNCTIONS_H
#define MATHFUNCTIONS_H

double sqrt_custom(double x);

#endif

MathFunctions.cpp

#include "MathFunctions.h"
#include <cmath>

double sqrt_custom(double x) {
        return std::sqrt(x);
    }

UseLib 代码文件

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

project(SquareRootApp)

# Set the output directory for the executable
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Create the executable and link against the DLL
add_executable(SquareRootApp src/main.cpp)

# Link the executable with the DLL
IF (WIN32)
  target_link_libraries(SquareRootApp PRIVATE ${CMAKE_SOURCE_DIR}/../CreateLib/build/lib/MathFunctions.dll)
ELSE()
  target_link_libraries(SquareRootApp PRIVATE ${CMAKE_SOURCE_DIR}/../CreateLib/build/lib/MathFunctions.so)
ENDIF()

# Include the directory containing the header files
target_include_directories(SquareRootApp PRIVATE ${CMAKE_SOURCE_DIR}/../CreateLib/include)

main.cpp

#include <iostream>
#include "MathFunctions.h"

int main() {
    double x = 16.0;
    double result = sqrt_custom(x);

    std::cout << "Square root of " << x << " is: " << result << std::endl;

    std::cin.get();

    return 0;
}

解决方案

1. 解决Windows链接错误LNK1107

Windows平台下链接DLL时,不能直接链接.dll文件,必须链接对应的导入库(.lib文件)——Visual Studio编译DLL时会生成两个文件:.dll是运行时依赖,.lib是链接时需要的导入库。

修改UseLib/CMakeLists.txt中的链接逻辑:

IF (WIN32)
  # 链接导入库.lib,而非.dll文件
  target_link_libraries(SquareRootApp PRIVATE ${CMAKE_SOURCE_DIR}/../CreateLib/build/lib/MathFunctions.lib)
ELSE()
  target_link_libraries(SquareRootApp PRIVATE ${CMAKE_SOURCE_DIR}/../CreateLib/build/lib/MathFunctions.so)
ENDIF()

另外,CreateLib的CMake配置里,CMAKE_LIBRARY_OUTPUT_DIRECTORY在Windows下默认输出DLL,而导入库.lib会生成在CMAKE_ARCHIVE_OUTPUT_DIRECTORY。可以统一输出目录避免找不到.lib:
在CreateLib/CMakeLists.txt中添加:

# 统一静态库(导入库)输出目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

这样.lib和.dll都会输出到build/lib目录,确保UseLib能找到正确的导入库。

2. 遵循CMake规范的优化方案

直接硬编码库路径不是CMake的最佳实践,推荐以下两种更可靠的方式:

方式一:用find_library自动定位库

修改UseLib/CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

project(SquareRootApp)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

add_executable(SquareRootApp src/main.cpp)

# 自动查找MathFunctions库,跨平台适配
find_library(MATH_FUNCTIONS_LIB
    NAMES MathFunctions MathFunctions.lib MathFunctions.so
    PATHS ${CMAKE_SOURCE_DIR}/../CreateLib/build/lib
)

# 链接找到的库
target_link_libraries(SquareRootApp PRIVATE ${MATH_FUNCTIONS_LIB})

# 包含头文件目录
target_include_directories(SquareRootApp PRIVATE ${CMAKE_SOURCE_DIR}/../CreateLib/include)

find_library会根据当前平台自动匹配对应的库文件(Windows找.lib,Linux找.so),无需手动判断平台。

方式二:将CreateLib作为子项目管理(推荐)

把CreateLib作为UseLib的子项目,CMake会自动构建依赖并管理路径:
在UseLib/CMakeLists.txt中添加:

# 添加子项目,指定构建目录
add_subdirectory(../CreateLib ${CMAKE_BINARY_DIR}/CreateLib)

之后直接用目标名链接,无需手动设置路径:

target_link_libraries(SquareRootApp PRIVATE MathFunctions)
# 头文件目录可通过子项目目标自动继承,无需手动设置

此外,CreateLib中的全局include_directories(include)建议改成目标级别的包含,符合现代CMake规范:

target_include_directories(MathFunctions PUBLIC include)

这样其他目标链接MathFunctions时,会自动继承其头文件目录,无需在UseLib中重复设置。


内容的提问来源于stack exchange,提问作者Scott G

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:35:57