1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.github.maven_nar.cpptasks.gcc;
21
22 import java.io.File;
23 import java.util.Vector;
24
25 import com.github.maven_nar.cpptasks.CCTask;
26 import com.github.maven_nar.cpptasks.CUtil;
27 import com.github.maven_nar.cpptasks.compiler.CaptureStreamHandler;
28 import com.github.maven_nar.cpptasks.compiler.LinkType;
29 import com.github.maven_nar.cpptasks.compiler.Linker;
30 import com.github.maven_nar.cpptasks.types.LibrarySet;
31
32
33
34
35
36
37 public class GppLinker extends AbstractLdLinker {
38 public static final String GPP_COMMAND = "g++";
39
40 protected static final String[] discardFiles = new String[0];
41 protected static final String[] objFiles = new String[] {
42 ".o", ".a", ".lib", ".dll", ".so", ".sl"
43 };
44 private final static String libPrefix = "libraries: =";
45 protected static final String[] libtoolObjFiles = new String[] {
46 ".fo", ".a", ".lib", ".dll", ".so", ".sl"
47 };
48 private static String[] linkerOptions = new String[] {
49 "-bundle", "-dylib", "-dynamic", "-dynamiclib", "-nostartfiles", "-nostdlib", "-prebind", "-s", "-static",
50 "-shared", "-symbolic", "-Xlinker", "-static-libgcc", "-shared-libgcc", "-p", "-pg", "-pthread"
51 };
52
53 private static final GppLinker soLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".so", false,
54 new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".so", true, null));
55 private static final GppLinker instance = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "", "", false, null);
56 private static final GppLinker clangInstance = new GppLinker("clang", objFiles, discardFiles, "", "", false, null);
57 private static final GppLinker machDllLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".dylib",
58 false, null);
59 private static final GppLinker machPluginLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib",
60 ".bundle", false, null);
61
62 private static final GppLinker machJNILinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".jnilib",
63 false, null);
64
65 private static final GppLinker dllLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "", ".dll", false, null);
66
67 public static GppLinker getCLangInstance() {
68 return clangInstance;
69 }
70
71 public static GppLinker getInstance() {
72 return instance;
73 }
74
75 private File[] libDirs;
76 private String runtimeLibrary;
77
78 private String gccLibrary, gfortranLibrary, gfortranMainLibrary;
79
80 protected GppLinker(final String command, final String[] extensions, final String[] ignoredExtensions,
81 final String outputPrefix, final String outputSuffix, final boolean isLibtool, final GppLinker libtoolLinker) {
82 super(command, "-dumpversion", extensions, ignoredExtensions, outputPrefix, outputSuffix, isLibtool, libtoolLinker);
83 }
84
85 @Override
86 protected void addImpliedArgs(final CCTask task, final boolean debug, final LinkType linkType,
87 final Vector<String> args) {
88 super.addImpliedArgs(task, debug, linkType, args);
89 if (getIdentifier().contains("mingw")) {
90 if (linkType.isSubsystemConsole()) {
91 args.addElement("-mconsole");
92 }
93 if (linkType.isSubsystemGUI()) {
94 args.addElement("-mwindows");
95 }
96 }
97
98
99
100 this.gfortranLibrary = null;
101 if (linkType.linkFortran()) {
102 if (linkType.isStaticRuntime()) {
103 final String[] cmdin = new String[] {
104 "gfortran", "-print-file-name=libgfortran.a"
105 };
106 final String[] cmdout = CaptureStreamHandler.run(cmdin);
107 if (cmdout.length > 0 && cmdout[0].indexOf('/') >= 0) {
108 this.gfortranLibrary = cmdout[0];
109 }
110 } else {
111 this.gfortranLibrary = "-lgfortran";
112 }
113 }
114
115 this.gfortranMainLibrary = null;
116 if (linkType.linkFortran()) {
117 if (linkType.isExecutable() && linkType.linkFortranMain() && !isDarwin()) {
118 if (linkType.isStaticRuntime()) {
119 final String[] cmdin = new String[] {
120 "gfortran", "-print-file-name=libgfortranbegin.a"
121 };
122 final String[] cmdout = CaptureStreamHandler.run(cmdin);
123 if (cmdout.length > 0 && cmdout[0].indexOf('/') >= 0) {
124 this.gfortranMainLibrary = cmdout[0];
125 }
126 } else {
127 this.gfortranMainLibrary = "-lgfortranbegin";
128 }
129 }
130 }
131
132 this.runtimeLibrary = null;
133 if (linkType.linkCPP()) {
134 if (linkType.isStaticRuntime()) {
135 if (isDarwin()) {
136 if (isClang()) {
137 task.log("Warning: clang cannot statically link to C++");
138 } else {
139 this.runtimeLibrary = "-lstdc++-static";
140 }
141 } else {
142 final String[] cmdin = new String[] {
143 "g++", "-print-file-name=libstdc++.a"
144 };
145 final String[] cmdout = CaptureStreamHandler.run(cmdin);
146 if (cmdout.length > 0 && cmdout[0].indexOf('/') >= 0) {
147 this.runtimeLibrary = cmdout[0];
148 }
149 }
150 } else {
151 this.runtimeLibrary = "-lstdc++";
152 }
153 }
154
155 this.gccLibrary = null;
156 if (linkType.isStaticRuntime()) {
157 if (isClang()) {
158 task.log("Warning: clang cannot statically link libgcc");
159 } else {
160 this.gccLibrary = "-static-libgcc";
161 }
162 } else {
163 if (linkType.linkCPP()) {
164
165 this.gccLibrary = "-fexceptions";
166 } else {
167 if (isClang()) {
168 task.log("Warning: clang cannot dynamically link libgcc");
169 } else {
170 this.gccLibrary = "-shared-libgcc";
171 }
172 }
173 }
174
175 }
176
177 @Override
178 protected String[] addLibrarySets(final CCTask task, final LibrarySet[] libsets, final Vector<String> preargs,
179 final Vector<String> midargs, final Vector<String> endargs) {
180 final String[] rs = super.addLibrarySets(task, libsets, preargs, midargs, endargs);
181
182 if (this.gfortranLibrary != null) {
183 endargs.addElement(this.gfortranLibrary);
184 }
185 if (this.gfortranMainLibrary != null) {
186 endargs.addElement(this.gfortranMainLibrary);
187 }
188 if (this.gccLibrary != null) {
189 endargs.addElement(this.gccLibrary);
190 }
191
192 if (this.runtimeLibrary != null) {
193 endargs.addElement(this.runtimeLibrary);
194 }
195 return rs;
196 }
197
198
199
200
201
202
203
204
205
206
207
208 @Override
209 public String decorateLinkerOption(final StringBuffer buf, final String arg) {
210 String decoratedArg = arg;
211 if (arg.length() > 1 && arg.charAt(0) == '-') {
212 switch (arg.charAt(1)) {
213
214
215
216 case 'g':
217 case 'f':
218 case 'F':
219
220 case 'm':
221 case 'O':
222 case 'W':
223 case 'l':
224 case 'L':
225 case 'u':
226 case 'B':
227 break;
228 default:
229 boolean known = false;
230 for (final String linkerOption : linkerOptions) {
231 if (linkerOption.equals(arg)) {
232 known = true;
233 break;
234 }
235 }
236 if (!known) {
237 buf.setLength(0);
238 buf.append("-Wl,");
239 buf.append(arg);
240 decoratedArg = buf.toString();
241 }
242 break;
243 }
244 }
245 return decoratedArg;
246 }
247
248
249
250
251
252 @Override
253 public File[] getLibraryPath() {
254 if (this.libDirs == null) {
255 final Vector<String> dirs = new Vector<>();
256
257 final String[] args = new String[] {
258 "g++", "-print-search-dirs"
259 };
260 final String[] cmdout = CaptureStreamHandler.run(args);
261 for (int i = 0; i < cmdout.length; ++i) {
262 final int prefixIndex = cmdout[i].indexOf(libPrefix);
263 if (prefixIndex >= 0) {
264
265 int s = prefixIndex + libPrefix.length();
266 int t = cmdout[i].indexOf(';', s);
267 while (t > 0) {
268 dirs.addElement(cmdout[i].substring(s, t));
269 s = t + 1;
270 t = cmdout[i].indexOf(';', s);
271 }
272 dirs.addElement(cmdout[i].substring(s));
273 ++i;
274 for (; i < cmdout.length; ++i) {
275 dirs.addElement(cmdout[i]);
276 }
277 }
278 }
279
280 final String[] libpath = new String[dirs.size()];
281 dirs.copyInto(libpath);
282 final int count = CUtil.checkDirectoryArray(libpath);
283
284 this.libDirs = new File[count];
285 int index = 0;
286 for (final String element : libpath) {
287 if (element != null) {
288 this.libDirs[index++] = new File(element);
289 }
290 }
291 }
292 return this.libDirs;
293 }
294
295 @Override
296 public Linker getLinker(final LinkType type) {
297 if (type.isStaticLibrary()) {
298 return GccLibrarian.getInstance();
299 }
300
301 if (type.isJNIModule()) {
302 return isDarwin() ? machJNILinker : isWindows() ? dllLinker : soLinker;
303 }
304 if (type.isPluginModule()) {
305 return isDarwin() ? machPluginLinker : isWindows() ? dllLinker : soLinker;
306 }
307 if (type.isSharedLibrary()) {
308 return isDarwin() ? machDllLinker : isWindows() ? dllLinker : soLinker;
309 }
310
311 return instance;
312 }
313
314
315
316
317
318 private boolean isClang() {
319 final String command = getCommand();
320 if (command == null) {
321 return false;
322 }
323 if (command.startsWith("clang")) {
324 return true;
325 }
326 if (!GPP_COMMAND.equals(command)) {
327 return false;
328 }
329 final String[] cmd = {
330 command, "--version"
331 };
332 final String[] cmdout = CaptureStreamHandler.execute(cmd).getStdout();
333 return cmdout != null && cmdout.length > 0 && cmdout[0].contains("(clang-");
334 }
335 }