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
相关产品推荐
相关产品推荐

