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

Nushell编译脚本中Clang链接阶段无法找到.o文件问题排查

问题

为C++项目编写Nushell构建脚本,架构为先编译库再编译关联可执行文件。库构建脚本负责定义编译/链接参数,并调用common.nu中定义的build函数。

库构建脚本代码:

# Build script for stowy physics engine

source ../common.nu

def main [buildType: string = 'debug'] {
    let isRelease = $buildType == 'release'

    # Setup flags
    let compilerFlags = [ '-std=c++20' (if $isRelease { '-O3' } else { '-g3' })]
    const includeFlags = ['-Isrc']
    const linkerFlags = ['-shared']
    let defines = ['-DSTWEXPORT' (if $isRelease { '-DNDEBUG'} else { '-DDEBUG' })]

    build stowy_physics_engine 'src/' '../bin/' $compilerFlags $includeFlags $linkerFlags $defines $buildType library
}

common.nu中的build函数代码:

# Builds the assembly according to the parameters
def build [
    assemblyName: string,
    sourceDirectory: path,
    binaryDirectory: path,
    compilerFlags: list<string>,
    includeFlags: list<string>,
    linkerFlags: list<string>,
    defines: list<string>,
    buildType: string = 'debug', # The optimisation level of the build. Can be 'release' or 'debug'.
    targetType: string = 'executable', # The type of target. Can be 'executable' or 'library'.
] {
    let isRelease = $buildType == 'release'

    let assemblyExtension = if $targetType == 'executable' {
        if ($env.OS | str contains 'Windows') { '.exe' } else { '' }
    } else if $targetType == 'library' {
        if ($env.OS | str contains 'Windows') { '.dll' } else { '.so' }
    } else {
        return 'Invalid targetType'
    }

    let assemblyOutputFile = $'($binaryDirectory)/($assemblyName)($assemblyExtension)'

    let cppFiles = glob **/*.cpp

    let relativeCppFiles = ($cppFiles  | path relative-to $sourceDirectory | path parse)

    # Build every .cpp to .o and get a list of every .o
    let objectFiles = $relativeCppFiles | each {|relativeCppFile| (
        # Convert from path object to string
        let inputFile = ($relativeCppFile | path join);
        let outputFile = ($relativeCppFile | upsert extension 'o' | path join);

        # Recreate the folder structure of .cpp files for the .o in the binary directory
        let inputDirectory = ($relativeCppFile | get parent);
        mkdir ($'($binaryDirectory)/($inputDirectory)');

        # concatenate the .o file with the bin directory
        let outputFileWithDir = $'($binaryDirectory)/($outputFile)'; # ex: ../bin/math/Vector2.o
        let sourceFileWithDir = $'($sourceDirectory)/($inputFile)'; # ex: src/math/Vector2.cpp

        clang++ -c -o $outputFileWithDir $sourceFileWithDir $defines $includeFlags $compilerFlags;
        $outputFileWithDir
    )}

    let startTime = date now

    clang++ -o $assemblyOutputFile $objectFiles $linkerFlags $includeFlags $defines $compilerFlags

    print $'Built and linked ($assemblyName) successfully.'
}

清空bin目录后执行脚本,链接阶段Clang报错找不到所有.o文件,错误信息如下:

Building stowy_physics_engine in debug...
Building C:\dev\cpp\build_system_tests\bin/collision\BroadPhaseGrid.o...
...
Building C:\dev\cpp\build_system_tests\bin/math\Vector2.o...
Built objects in 266ms 309µs 700ns
Linking...
clang++: error: no such file or directory: 'C:\dev\cpp\build_system_tests\bin/collision\BroadPhaseGrid.o'
...
clang++: error: no such file or directory: 'C:\dev\cpp\build_system_tests\bin/math\Vector2.o'
clang++: error: no input files

怀疑链接命令在编译完成前就已执行,请问该问题的成因是什么?

成因分析

问题核心在于Nushell的each命令默认是并行执行的:

  • 当通过$relativeCppFiles | each { ... }循环编译.cpp文件时,Nushell会同时启动多个clang++进程生成.o文件,不会等待所有编译任务完成,就会把所有预期的.o文件路径收集到objectFiles变量中。
  • 后续的链接命令会立即执行,此时部分(甚至全部).o文件还没生成完毕,Clang自然找不到对应的文件,抛出"no such file or directory"错误。

另外,并行执行还会引发次生问题:多个编译进程同时尝试创建同一个目录时,mkdir命令会报错,进一步阻碍.o文件的生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:34:55