PowerShell 脚本的后缀是 .ps1
前提:
ps1 脚本可以帮忙我们快速修改文件内容,还不需要调用文件的底层 api,方便快捷
在编写 CMakeLists 时发现,项目不能够很好的使用 vcpkg tool chain,哪怕是在命令行中指定 vcpkg.cmake
如果只是简单的项目,vcpkg tool chain 可以正常工作,但是在稍微复杂一些的项目中,比如依赖的 vcpkg 的库过多,就会发现在编译时提示找不到相关的库
不过总的来说,这些都不是本文的重点,重点是如何编写好一个 ps1 脚本
正文:
我们需要读取一个文件的内容,并修改文件中的某个变量名,以及在特定的上下文中插入自定义字符串
# 读取项目文件内容 $scriptDir = $PSScriptRoot $vcxprojPath = Join-Path $scriptDir "\build\project.vcxproj" $vcxprojContent = Get-Content $vcxprojPath # 定义常量 $configurationPlatformDebug = '"''$(Configuration)|$(Platform)''==''Debug|Win32''"' $configurationPlatformRelease = '"''$(Configuration)|$(Platform)''==''Release|Win32''"' # 添加 Vcpkg $targetLine1 = ' <GenerateManifest Condition=' + $configurationPlatformRelease + '>true</GenerateManifest>' $targetLine2 = ' </PropertyGroup>' # 修改 Debug 配置 $targetLine3 = ' <OutDir Condition=' + $configurationPlatformDebug + '>' + (Join-Path $scriptDir "build\Debug\") + '</OutDir>' $targetLine4 = ' <IntDir Condition=' + $configurationPlatformDebug + '>project.dir\Debug\</IntDir>' $targetLine5 = ' <TargetName Condition=' + $configurationPlatformDebug + '>project</TargetName>' # 修改 Release 配置 $targetLine6 = ' <OutDir Condition=' + $configurationPlatformRelease + '>' + (Join-Path $scriptDir "build\Release\") + '</OutDir>' $targetLine7 = ' <IntDir Condition=' + $configurationPlatformRelease + '>project.dir\Release\</IntDir>' $targetLine8 = ' <TargetName Condition=' + $configurationPlatformRelease + '>project</TargetName>' $targetLine9 = ' <PropertyGroup Condition=' + $configurationPlatformRelease + ' Label="Configuration">' $targetLine10 = ' <TargetExt Condition=' + $configurationPlatformRelease + '>.exe</TargetExt>' # 要替换的新文本 $newAttributes = @" <PropertyGroup Label="Vcpkg" Condition=$configurationPlatformDebug> <VcpkgConfiguration>Debug</VcpkgConfiguration> </PropertyGroup> <PropertyGroup Label="Globals"> <VcpkgTriplet Condition="'`$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet> </PropertyGroup> "@ $newTargetLines3 = ' <OutDir Condition=' + $configurationPlatformDebug + '>$(SolutionDir)bin\$(Configuration)\</OutDir>' $newTargetLines4 = ' <IntDir Condition=' + $configurationPlatformDebug + '>$(SolutionDir)temp\$(Configuration)\$(ProjectName)\</IntDir>' $newTargetLines5 = ' <TargetName Condition=' + $configurationPlatformDebug + '>$(SolutionName)_d</TargetName>' $newTargetLines6 = ' <OutDir Condition=' + $configurationPlatformRelease + '>$(SolutionDir)bin\Project\$(PJVersion)\</OutDir>' $newTargetLines7 = ' <IntDir Condition=' + $configurationPlatformRelease + '>$(SolutionDir)temp\$(Configuration)\$(ProjectName)\</IntDir>' $newTargetLines8 = ' <TargetName Condition=' + $configurationPlatformRelease + '>$(SolutionName)</TargetName>' $newTargetLines9 = ' <ConfigurationType>DynamicLibrary</ConfigurationType>' $newTargetLines10 = ' <TargetExt Condition=' + $configurationPlatformRelease + '>.dll</TargetExt>' $foundLines = @() # 因为只遍历一遍,所以要按先后顺序放置待修改的行 for ($i = 0; $i -lt $vcxprojContent.Length - 1; $i++) { $line = $vcxprojContent[$i] # 检查是否找到目标行 if ($line -eq $targetLine9) { $foundLines += $i + 1 } if ($line -eq $targetLine3) { $foundLines += $i } if ($line -eq $targetLine4) { $foundLines += $i } if ($line -eq $targetLine5) { $foundLines += $i } if ($line -eq $targetLine6) { $foundLines += $i } if ($line -eq $targetLine7) { $foundLines += $i } if ($line -eq $targetLine8) { $foundLines += $i } if ($line -eq $targetLine10) { $foundLines += $i } if ($line -eq $targetLine1 -and $vcxprojContent[$i + 1] -eq $targetLine2) { $foundLines += $i + 2 } } # 判断是否找到所有待替换的行 if ($foundLines.Count -eq 9) { # 替换目标行 $vcxprojContent[$foundLines[0]] = $newTargetLines9 $vcxprojContent[$foundLines[1]] = $newTargetLines3 $vcxprojContent[$foundLines[2]] = $newTargetLines4 $vcxprojContent[$foundLines[3]] = $newTargetLines5 $vcxprojContent[$foundLines[4]] = $newTargetLines6 $vcxprojContent[$foundLines[5]] = $newTargetLines7 $vcxprojContent[$foundLines[6]] = $newTargetLines8 $vcxprojContent[$foundLines[7]] = $newTargetLines10 # 在目标行后面插入新文本 $vcxprojContent = [System.Collections.ArrayList]($vcxprojContent -split "`r`n") $vcxprojContent.Insert($foundLines[8], $newAttributes) # 将修改后的内容保存回文件 $vcxprojContent | ForEach-Object { $_ } | Set-Content $vcxprojPath Write-Host "Target lines replaced successfully in project." } else { Write-Host "Specific lines not found in the file in project." }
我们还可以通过 ps1 脚本改文件编码格式
比如 visual studio 默认接受 UTF-16 编码的 rc 文件,而我们使用 CMake 中的 configure_file 函数生成的文件默认是 UTF-8 编码
那么我们可以使用 -Encoding 来改变
# project.rc 转为 UTF-16 编码 $rcPath = Join-Path $scriptDir "\build\project.rc" # 读取 UTF-8 编码的文件内容 $content = Get-Content -Path $rcPath -Encoding UTF8 # 将内容以 UTF-16 编码保存 Set-Content -Path $rcPath -Value $content -Encoding Unicode
补充:
时间匆忙,无法对每个 ps1 的函数一一讲解,有兴趣的可以查阅文档来了解其作用
标签:脚本,project,Path,编写,line,foundLines,eq,PowerShell,vcxprojContent From: https://www.cnblogs.com/strive-sun/p/17968286