@@ -137,6 +137,8 @@ export async function getWindowsCrossCompileArgs(runtime: string): Promise<{
137137 args : string [ ] ;
138138 env : Record < string , string > ;
139139 error ?: string ;
140+ /** 临时 props 文件路径,需要在构建后删除 */
141+ tempPropsFile ?: string ;
140142} > {
141143 const sdkPath = getXwinSdkPath ( ) ;
142144 const splatPath = path . join ( sdkPath , 'splat' ) ;
@@ -194,13 +196,9 @@ export async function getWindowsCrossCompileArgs(runtime: string): Promise<{
194196 sdkUcrtPath ,
195197 ] . filter ( p => fs . existsSync ( p ) ) ;
196198
197- // 通过 IlcAdditionalLinkArgs 传递链接器参数
198- // 使用分号分隔多个参数,避免空格被 MSBuild 误解
199- const linkerArgs = libPaths . map ( p => `/LIBPATH:${ p } ` ) . join ( ';' ) ;
200- args . push ( `-p:IlcAdditionalLinkArgs="${ linkerArgs } "` ) ;
201-
202- // 构建 LIB 环境变量 - lld-link 需要这个来查找库
203- const libEnvPaths = libPaths . join ( path . delimiter ) ;
199+ // 设置 LIB 环境变量
200+ // 注意:lld-link 是 Windows 工具,期望使用分号 (;) 分隔路径,而不是 macOS 的冒号 (:)
201+ const libEnvPaths = libPaths . join ( ';' ) ;
204202
205203 // 添加 lld-link 到 PATH
206204 const brewPrefix = process . arch === 'arm64' ? '/opt/homebrew' : '/usr/local' ;
@@ -217,6 +215,123 @@ export async function getWindowsCrossCompileArgs(runtime: string): Promise<{
217215 return { success : true , args, env } ;
218216}
219217
218+ /**
219+ * 临时 props 文件管理
220+ */
221+ export interface TempPropsFileResult {
222+ /** 创建的文件路径 */
223+ propsFilePath : string ;
224+ /** 原始文件的备份路径(如果需要备份) */
225+ backupFilePath ?: string ;
226+ /** 是否需要恢复原始文件 */
227+ needsRestore : boolean ;
228+ }
229+
230+ /**
231+ * 创建临时的 Directory.Build.props 文件用于设置链接器参数
232+ * @param projectDir 项目目录
233+ * @param runtime 目标运行时
234+ * @returns 创建的文件信息,或 null 如果失败
235+ */
236+ export function createTempLinkerPropsFile ( projectDir : string , runtime : string ) : TempPropsFileResult | null {
237+ const sdkPath = getXwinSdkPath ( ) ;
238+ const splatPath = path . join ( sdkPath , 'splat' ) ;
239+ const arch = getWindowsArch ( runtime ) ;
240+
241+ const crtLibPath = path . join ( splatPath , 'crt' , 'lib' , arch ) ;
242+ const sdkUmPath = path . join ( splatPath , 'sdk' , 'lib' , 'um' , arch ) ;
243+ const sdkUcrtPath = path . join ( splatPath , 'sdk' , 'lib' , 'ucrt' , arch ) ;
244+
245+ const libPaths = [ crtLibPath , sdkUmPath , sdkUcrtPath ] . filter ( p => fs . existsSync ( p ) ) ;
246+
247+ if ( libPaths . length === 0 ) {
248+ return null ;
249+ }
250+
251+ // 构建 LinkerArg ItemGroup
252+ const linkerArgs = libPaths . map ( p => ` <LinkerArg Include="/LIBPATH:${ p } " />` ) . join ( '\n' ) ;
253+
254+ // 必须使用 Directory.Build.props 这个名称,MSBuild 才会自动导入
255+ const propsFileName = 'Directory.Build.props' ;
256+ const propsFilePath = path . join ( projectDir , propsFileName ) ;
257+ const backupFilePath = path . join ( projectDir , 'Directory.Build.props.dotnet-deploy-backup' ) ;
258+
259+ let needsRestore = false ;
260+ let originalContent : string | null = null ;
261+
262+ // 检查是否已存在 Directory.Build.props
263+ if ( fs . existsSync ( propsFilePath ) ) {
264+ // 备份现有文件
265+ try {
266+ originalContent = fs . readFileSync ( propsFilePath , 'utf8' ) ;
267+ fs . writeFileSync ( backupFilePath , originalContent , 'utf8' ) ;
268+ needsRestore = true ;
269+ } catch {
270+ // 如果无法备份,不继续
271+ return null ;
272+ }
273+
274+ // 尝试在现有文件中添加我们的 ItemGroup
275+ // 查找 </Project> 结束标签并在之前插入
276+ const insertIndex = originalContent . lastIndexOf ( '</Project>' ) ;
277+ if ( insertIndex !== - 1 ) {
278+ const newContent = originalContent . slice ( 0 , insertIndex ) +
279+ ` <!-- Auto-generated by vscode-dotnet-deploy for cross-compilation -->
280+ <ItemGroup Condition="'$(PublishAot)' == 'true' and '$(RuntimeIdentifier)' == '${ runtime } '">
281+ ${ linkerArgs }
282+ </ItemGroup>
283+ ` + originalContent . slice ( insertIndex ) ;
284+ try {
285+ fs . writeFileSync ( propsFilePath , newContent , 'utf8' ) ;
286+ return { propsFilePath, backupFilePath, needsRestore } ;
287+ } catch {
288+ // 恢复原始文件
289+ if ( needsRestore ) {
290+ fs . writeFileSync ( propsFilePath , originalContent , 'utf8' ) ;
291+ }
292+ return null ;
293+ }
294+ }
295+ }
296+
297+ // 创建新的 Directory.Build.props 文件
298+ const propsContent = `<?xml version="1.0" encoding="utf-8"?>
299+ <!-- Auto-generated by vscode-dotnet-deploy for cross-compilation -->
300+ <Project>
301+ <ItemGroup Condition="'$(PublishAot)' == 'true' and '$(RuntimeIdentifier)' == '${ runtime } '">
302+ ${ linkerArgs }
303+ </ItemGroup>
304+ </Project>
305+ ` ;
306+
307+ try {
308+ fs . writeFileSync ( propsFilePath , propsContent , 'utf8' ) ;
309+ return { propsFilePath, backupFilePath : needsRestore ? backupFilePath : undefined , needsRestore } ;
310+ } catch {
311+ return null ;
312+ }
313+ }
314+
315+ /**
316+ * 删除或恢复临时 props 文件
317+ */
318+ export function removeTempLinkerPropsFile ( result : TempPropsFileResult ) : void {
319+ try {
320+ if ( result . needsRestore && result . backupFilePath && fs . existsSync ( result . backupFilePath ) ) {
321+ // 恢复原始文件
322+ const originalContent = fs . readFileSync ( result . backupFilePath , 'utf8' ) ;
323+ fs . writeFileSync ( result . propsFilePath , originalContent , 'utf8' ) ;
324+ // 删除备份
325+ fs . unlinkSync ( result . backupFilePath ) ;
326+ } else if ( fs . existsSync ( result . propsFilePath ) ) {
327+ // 删除创建的文件
328+ fs . unlinkSync ( result . propsFilePath ) ;
329+ }
330+ } catch {
331+ // 忽略错误
332+ }
333+ }
334+
220335/**
221336 * 验证 Windows SDK 完整性
222337 */
0 commit comments