@@ -25,185 +25,158 @@ extension WindowsToolchain {
2525 targetInfo: FrontendTargetInfo
2626 ) throws -> AbsolutePath {
2727 let targetTriple = targetInfo. target. triple
28+
2829 switch linkerOutputType {
2930 case . dynamicLibrary:
30- commandLine. appendFlags ( " -parse-as-library " , " -emit-library " )
31+ commandLine. appendFlags ( " -Xlinker " , " -dll " )
32+ fallthrough
3133 case . executable:
3234 if !targetTriple. triple. isEmpty {
3335 commandLine. appendFlag ( " -target " )
3436 commandLine. appendFlag ( targetTriple. triple)
3537 }
36- commandLine. appendFlag ( " -emit-executable " )
37- default :
38- break
39- }
40-
41- switch linkerOutputType {
42- case . staticLibrary:
43- commandLine. append ( . joinedOptionAndPath( " -out: " , outputFile) )
44- commandLine. append ( contentsOf: inputs. map { . path( $0. file) } )
45- if commandLine. contains ( . flag( " -use-ld=lld " ) ) {
46- return try lookup ( executable: " llvm-lib.exe " )
47- }
48- return try getToolPath ( . staticLinker)
49- // TODO: Check for `-use-ld=lld`.
50- default :
51- // Configure the toolchain.
52- //
53- // By default use the system `clang` to perform the link. We use `clang` for
54- // the driver here because we do not wish to select a particular C++ runtime.
55- // Furthermore, until C++ interop is enabled, we cannot have a dependency on
56- // C++ code from pure Swift code. If linked libraries are C++ based, they
57- // should properly link C++. In the case of static linking, the user can
58- // explicitly specify the C++ runtime to link against. This is particularly
59- // important for platforms like android where as it is a Linux platform, the
60- // default C++ runtime is `libstdc++` which is unsupported on the target but
61- // as the builds are usually cross-compiled from Linux, libstdc++ is going to
62- // be present. This results in linking the wrong version of libstdc++
63- // generating invalid binaries. It is also possible to use different C++
64- // runtimes than the default C++ runtime for the platform (e.g. libc++ on
65- // Windows rather than msvcprt). When C++ interop is enabled, we will need to
66- // surface this via a driver flag. For now, opt for the simpler approach of
67- // just using `clang` and avoid a dependency on the C++ runtime.
68- var clangPath = try getToolPath ( . clang)
69- if let toolsDirPath = parsedOptions. getLastArgument ( . toolsDirectory) {
70- // FIXME: What if this isn't an absolute path?
71- let toolsDir = try AbsolutePath ( validating: toolsDirPath. asSingle)
72-
73- // If there is a clang in the toolchain folder, use that instead.
74- if let tool = lookupExecutablePath ( filename: " clang.exe " , searchPaths: [ toolsDir] ) {
75- clangPath = tool
76- }
77-
78- // Look for binutils in the toolchain folder.
79- commandLine. appendFlag ( " -B " )
80- commandLine. appendPath ( toolsDir)
38+ // Configure the toolchain.
39+ //
40+ // By default use the system `clang` to perform the link. We use `clang` for
41+ // the driver here because we do not wish to select a particular C++ runtime.
42+ // Furthermore, until C++ interop is enabled, we cannot have a dependency on
43+ // C++ code from pure Swift code. If linked libraries are C++ based, they
44+ // should properly link C++. In the case of static linking, the user can
45+ // explicitly specify the C++ runtime to link against. This is particularly
46+ // important for platforms like android where as it is a Linux platform, the
47+ // default C++ runtime is `libstdc++` which is unsupported on the target but
48+ // as the builds are usually cross-compiled from Linux, libstdc++ is going to
49+ // be present. This results in linking the wrong version of libstdc++
50+ // generating invalid binaries. It is also possible to use different C++
51+ // runtimes than the default C++ runtime for the platform (e.g. libc++ on
52+ // Windows rather than msvcprt). When C++ interop is enabled, we will need to
53+ // surface this via a driver flag. For now, opt for the simpler approach of
54+ // just using `clang` and avoid a dependency on the C++ runtime.
55+ var clangPath = try getToolPath ( . clang)
56+ if let toolsDirPath = parsedOptions. getLastArgument ( . toolsDirectory) {
57+ // FIXME: What if this isn't an absolute path?
58+ let toolsDir = try AbsolutePath ( validating: toolsDirPath. asSingle)
59+
60+ // If there is a clang in the toolchain folder, use that instead.
61+ if let tool = lookupExecutablePath ( filename: " clang.exe " , searchPaths: [ toolsDir] ) {
62+ clangPath = tool
8163 }
8264
83- let staticStdlib = parsedOptions. hasFlag ( positive: . staticStdlib,
84- negative: . noStaticStdlib,
85- default: false )
86- let staticExecutable = parsedOptions. hasFlag ( positive: . staticExecutable,
87- negative: . noStaticExecutable,
88- default: false )
89- let hasRuntimeArgs = !( staticStdlib || staticExecutable)
90-
91- let runtimePaths = try runtimeLibraryPaths (
92- for: targetTriple,
93- parsedOptions: & parsedOptions,
94- sdkPath: sdkPath,
95- isShared: hasRuntimeArgs
96- )
97-
98- let sharedResourceDirPath = try computeResourceDirPath (
99- for: targetTriple,
100- parsedOptions: & parsedOptions,
101- isShared: true
102- )
103-
104- let swiftrtPath = sharedResourceDirPath. appending (
105- components: " windows " , targetTriple. archName, " swiftrt.obj "
106- )
107- commandLine. appendPath ( swiftrtPath)
108-
109- let inputFiles : [ Job . ArgTemplate ] = inputs. compactMap { input in
110- // Autolink inputs are handled specially
111- if input. type == . autolink {
112- return . responseFilePath( input. file)
113- } else if input. type == . object {
114- return . path( input. file)
115- } else {
116- return nil
117- }
118- }
119- commandLine. append ( contentsOf: inputFiles)
120-
121- let fSystemArgs = parsedOptions. arguments ( for: . F, . Fsystem)
122- for opt in fSystemArgs {
123- if opt. option == . Fsystem {
124- commandLine. appendFlag ( " -iframework " )
125- } else {
126- commandLine. appendFlag ( . F)
127- }
128- commandLine. appendPath ( try VirtualPath ( path: opt. argument. asSingle) )
129- }
130-
131- // Add the runtime library link paths.
132- for path in runtimePaths {
133- commandLine. appendFlag ( . L)
134- commandLine. appendPath ( path)
135- }
65+ // Look for binutils in the toolchain folder.
66+ commandLine. appendFlag ( " -B " )
67+ commandLine. appendPath ( toolsDir)
68+ }
13669
137- // Link the standard library. In two paths, we do this using a .lnk file
138- // if we're going that route, we'll set `linkFilePath` to the path to that
139- // file.
140- var linkFilePath : AbsolutePath ? = try computeResourceDirPath (
141- for: targetTriple,
142- parsedOptions: & parsedOptions,
143- isShared: false
144- )
145-
146- if staticExecutable {
147- linkFilePath = linkFilePath? . appending ( component: " static-executable-args.lnk " )
148- } else if staticStdlib {
149- linkFilePath = linkFilePath? . appending ( component: " static-stdlib-args.lnk " )
70+ let linker : String
71+ if let arg = parsedOptions. getLastArgument ( . useLd) {
72+ linker = arg. asSingle
73+ } else {
74+ linker = " link "
75+ }
76+ commandLine. appendFlag ( " -fuse-ld= \( linker) " )
77+
78+ let staticStdlib = parsedOptions. hasFlag ( positive: . staticStdlib,
79+ negative: . noStaticStdlib,
80+ default: false )
81+ let staticExecutable = parsedOptions. hasFlag ( positive: . staticExecutable,
82+ negative: . noStaticExecutable,
83+ default: false )
84+ let hasRuntimeArgs = !( staticStdlib || staticExecutable)
85+
86+ let runtimePaths = try runtimeLibraryPaths (
87+ for: targetTriple,
88+ parsedOptions: & parsedOptions,
89+ sdkPath: sdkPath,
90+ isShared: hasRuntimeArgs
91+ )
92+
93+ let sharedResourceDirPath = try computeResourceDirPath (
94+ for: targetTriple,
95+ parsedOptions: & parsedOptions,
96+ isShared: true
97+ )
98+
99+ let swiftrtPath = sharedResourceDirPath. appending (
100+ components: targetTriple. archName, " swiftrt.obj "
101+ )
102+ commandLine. appendPath ( swiftrtPath)
103+
104+ let inputFiles : [ Job . ArgTemplate ] = inputs. compactMap { input in
105+ // Autolink inputs are handled specially
106+ if input. type == . autolink {
107+ return . responseFilePath( input. file)
108+ } else if input. type == . object {
109+ return . path( input. file)
150110 } else {
151- linkFilePath = nil
152- commandLine. appendFlag ( " -lswiftCore " )
111+ return nil
153112 }
113+ }
114+ commandLine. append ( contentsOf: inputFiles)
154115
155- if let linkFile = linkFilePath {
156- guard fileSystem. isFile ( linkFile) else {
157- fatalError ( " \( linkFile. pathString) not found " )
158- }
159- commandLine. append ( . responseFilePath( . absolute( linkFile) ) )
116+ let fSystemArgs = parsedOptions. arguments ( for: . F, . Fsystem)
117+ for opt in fSystemArgs {
118+ if opt. option == . Fsystem {
119+ commandLine. appendFlag ( " -iframework " )
120+ } else {
121+ commandLine. appendFlag ( . F)
160122 }
123+ commandLine. appendPath ( try VirtualPath ( path: opt. argument. asSingle) )
124+ }
161125
162- // Explicitly pass the target to the linker
163- commandLine. appendFlag ( " --target= \( targetTriple. triple) " )
164-
165- // Delegate to Clang for sanitizers. It will figure out the correct linker
166- // options.
167- if linkerOutputType == . executable && !sanitizers. isEmpty {
168- let sanitizerNames = sanitizers
169- . map { $0. rawValue }
170- . sorted ( ) // Sort so we get a stable, testable order
171- . joined ( separator: " , " )
172- commandLine. appendFlag ( " -fsanitize= \( sanitizerNames) " )
173-
174- // The TSan runtime depends on the blocks runtime and libdispatch.
175- if sanitizers. contains ( . thread) {
176- commandLine. appendFlag ( " -lBlocksRuntime " )
177- commandLine. appendFlag ( " -ldispatch " )
178- }
179- }
126+ // Add the runtime library link paths.
127+ for path in runtimePaths {
128+ commandLine. appendFlag ( . L)
129+ commandLine. appendPath ( path)
130+ }
180131
181- if parsedOptions. hasArgument ( . profileGenerate) {
182- let libProfile = sharedResourceDirPath
183- . parentDirectory // remove platform name
184- . appending ( components: " clang " , " lib " , targetTriple. osName,
185- " libclangrt_profile- \( targetTriple. archName) .a " )
186- commandLine. appendPath ( libProfile)
132+ if hasRuntimeArgs {
133+ commandLine. appendFlag ( " -lswiftCore " )
134+ }
187135
188- // HACK: Hard-coded from llvm::getInstrProfRuntimeHookVarName()
189- commandLine. appendFlag ( " -u__llvm_profile_runtime " )
136+ // Explicitly pass the target to the linker
137+ commandLine. appendFlags ( " -target " , targetTriple. triple)
138+
139+ // Delegate to Clang for sanitizers. It will figure out the correct linker
140+ // options.
141+ if linkerOutputType == . executable && !sanitizers. isEmpty {
142+ let sanitizerNames = sanitizers
143+ . map { $0. rawValue }
144+ . sorted ( ) // Sort so we get a stable, testable order
145+ . joined ( separator: " , " )
146+ commandLine. appendFlag ( " -fsanitize= \( sanitizerNames) " )
147+
148+ // The TSan runtime depends on the blocks runtime and libdispatch.
149+ if sanitizers. contains ( . thread) {
150+ commandLine. appendFlag ( " -lBlocksRuntime " )
151+ commandLine. appendFlag ( " -ldispatch " )
190152 }
153+ }
154+
155+ if parsedOptions. hasArgument ( . profileGenerate) {
156+ let libProfile = try clangLibraryPath ( for: targetTriple, parsedOptions: & parsedOptions)
157+ . appending ( components: " clang_rt.profile- \( archName ( for: targetTriple) ) .lib " )
158+ commandLine. appendPath ( libProfile)
159+ }
191160
192- // Run clang++ in verbose mode if "-v" is set
193- try commandLine. appendLast ( . v, from: & parsedOptions)
194-
195- // These custom arguments should be right before the object file at the
196- // end.
197- try commandLine. append (
198- contentsOf: parsedOptions. arguments ( in: . linkerOption)
199- )
200- try commandLine. appendAllArguments ( . Xlinker, from: & parsedOptions)
201- try commandLine. appendAllArguments ( . XclangLinker, from: & parsedOptions)
202-
203- // This should be the last option, for convenience in checking output.
204- commandLine. appendFlag ( . o)
205- commandLine. appendPath ( outputFile)
206- return clangPath
161+ // Run clang++ in verbose mode if "-v" is set
162+ try commandLine. appendLast ( . v, from: & parsedOptions)
163+
164+ // These custom arguments should be right before the object file at the
165+ // end.
166+ try commandLine. append (
167+ contentsOf: parsedOptions. arguments ( in: . linkerOption)
168+ )
169+ try commandLine. appendAllArguments ( . Xlinker, from: & parsedOptions)
170+ try commandLine. appendAllArguments ( . XclangLinker, from: & parsedOptions)
171+
172+ // This should be the last option, for convenience in checking output.
173+ commandLine. appendFlag ( . o)
174+ commandLine. appendPath ( outputFile)
175+ return clangPath
176+ case . staticLibrary:
177+ commandLine. append ( . joinedOptionAndPath( " -out: " , outputFile) )
178+ commandLine. append ( contentsOf: inputs. map { . path( $0. file) } )
179+ return try getToolPath ( . staticLinker)
207180 }
208181 }
209182}
0 commit comments