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;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.HashSet;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Set;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
31 import org.apache.maven.plugin.MojoExecutionException;
32 import org.apache.maven.plugin.MojoFailureException;
33 import org.apache.maven.plugin.logging.Log;
34 import org.apache.maven.plugins.annotations.Parameter;
35 import org.apache.tools.ant.Project;
36 import org.codehaus.plexus.util.FileUtils;
37
38 import com.github.maven_nar.cpptasks.CCTask;
39 import com.github.maven_nar.cpptasks.CUtil;
40 import com.github.maven_nar.cpptasks.LinkerDef;
41 import com.github.maven_nar.cpptasks.LinkerEnum;
42 import com.github.maven_nar.cpptasks.types.LibrarySet;
43 import com.github.maven_nar.cpptasks.types.LibraryTypeEnum;
44 import com.github.maven_nar.cpptasks.types.LinkerArgument;
45 import com.github.maven_nar.cpptasks.types.SystemLibrarySet;
46
47
48
49
50
51
52 public class Linker {
53
54
55
56
57
58
59 @Parameter
60 private String name;
61
62
63
64
65 @Parameter
66 private String prefix;
67
68
69
70
71 @Parameter
72 private String toolPath;
73
74
75
76
77 @Parameter(required = true)
78 private boolean incremental = false;
79
80
81
82
83 @Parameter(required = true)
84 private boolean map = false;
85
86 @Parameter(required = true)
87 private boolean skipDepLink = false;
88
89
90
91
92
93 @Parameter
94 private List options;
95
96
97
98
99
100
101 @Parameter
102 private List testOptions;
103
104
105
106
107
108
109 @Parameter
110 private String optionSet;
111
112
113
114
115 @Parameter(required = true)
116 private boolean clearDefaultOptions;
117
118
119
120
121 @Parameter
122 private List
123
124
125
126
127
128
129
130 @Parameter
131 private String libSet;
132
133
134
135
136 @Parameter
137 private List
138
139
140
141
142
143
144
145 @Parameter
146 private String sysLibSet;
147
148
149
150
151
152
153
154
155
156
157
158
159 @Parameter
160 private String narDependencyLibOrder;
161
162
163
164
165
166 @Parameter(property = "nar.generateManifest", defaultValue = "true")
167 private boolean generateManifest = true;
168
169 private final Log log;
170
171 public Linker() {
172
173 this(null);
174 }
175
176 public Linker(final Log log) {
177 this.log = log;
178 }
179
180
181
182
183
184
185 public Linker(final String name, final Log log) {
186 this.name = name;
187 this.log = log;
188 }
189
190 private void addLibraries(final String libraryList, final LinkerDef linker, final Project antProject,
191 final boolean isSystem) {
192
193 if (libraryList == null) {
194 return;
195 }
196
197 final String[] lib = libraryList.split(",");
198
199 for (final String element : lib) {
200
201 final String[] libInfo = element.trim().split(":", 3);
202
203 LibrarySet librarySet = new LibrarySet();
204
205 if (isSystem) {
206 librarySet = new SystemLibrarySet();
207 }
208
209 librarySet.setProject(antProject);
210 librarySet.setLibs(new CUtil.StringArrayBuilder(libInfo[0]));
211
212 if (libInfo.length > 1) {
213
214 final LibraryTypeEnum libType = new LibraryTypeEnum();
215
216 libType.setValue(libInfo[1]);
217 librarySet.setType(libType);
218
219 if (!isSystem && libInfo.length > 2) {
220 librarySet.setDir(new File(libInfo[2]));
221 }
222 }
223
224 if (!isSystem) {
225 linker.addLibset(librarySet);
226 } else {
227 linker.addSyslibset((SystemLibrarySet) librarySet);
228 }
229 }
230 }
231
232
233
234
235 public boolean isGenerateManifest() {
236 return generateManifest;
237 }
238
239 public final LinkerDef getLinker(final AbstractCompileMojo mojo, final CCTask task, final String os,
240 final String prefix, final String type) throws MojoFailureException, MojoExecutionException {
241 Project antProject = task.getProject();
242 if (this.name == null) {
243 throw new MojoFailureException("NAR: Please specify a <Name> as part of <Linker>");
244 }
245
246 final LinkerDef linker = new LinkerDef();
247 linker.setProject(antProject);
248 final LinkerEnum linkerEnum = new LinkerEnum();
249 linkerEnum.setValue(this.name);
250 linker.setName(linkerEnum);
251
252
253 if (this.toolPath != null) {
254 linker.setToolPath(this.toolPath);
255 } else if ("msvc".equalsIgnoreCase(name)) {
256 linker.setToolPath(mojo.getMsvc().getToolPath());
257 }
258
259 linker.setSkipDepLink(this.skipDepLink);
260
261
262 linker.setLinkerPrefix(this.prefix);
263 linker.setIncremental(this.incremental);
264 linker.setMap(this.map);
265
266
267 if (os.equals(OS.WINDOWS) && getName(null, null).equals("msvc")
268 && (type.equals(Library.SHARED) || type.equals(Library.JNI))) {
269 final Set defs = new HashSet();
270 try {
271 if (mojo.getC() != null) {
272 final List cSrcDirs = mojo.getC().getSourceDirectories();
273 for (final Object cSrcDir : cSrcDirs) {
274 final File dir = (File) cSrcDir;
275 if (dir.exists()) {
276 defs.addAll(FileUtils.getFiles(dir, "**/*.def", null));
277 }
278 }
279 }
280 } catch (final IOException e) {
281 }
282 try {
283 if (mojo.getCpp() != null) {
284 final List cppSrcDirs = mojo.getCpp().getSourceDirectories();
285 for (final Object cppSrcDir : cppSrcDirs) {
286 final File dir = (File) cppSrcDir;
287 if (dir.exists()) {
288 defs.addAll(FileUtils.getFiles(dir, "**/*.def", null));
289 }
290 }
291 }
292 } catch (final IOException e) {
293 }
294 try {
295 if (mojo.getFortran() != null) {
296 final List fortranSrcDirs = mojo.getFortran().getSourceDirectories();
297 for (final Object fortranSrcDir : fortranSrcDirs) {
298 final File dir = (File) fortranSrcDir;
299 if (dir.exists()) {
300 defs.addAll(FileUtils.getFiles(dir, "**/*.def", null));
301 }
302 }
303 }
304 } catch (final IOException e) {
305 }
306
307 for (final Object def : defs) {
308 final LinkerArgument arg = new LinkerArgument();
309 arg.setValue("/def:" + def);
310 linker.addConfiguredLinkerArg(arg);
311 }
312 }
313
314
315
316 if (os.equals(OS.WINDOWS) && getName(null, null).equals("msvc") && !getVersion(mojo).startsWith("6.")
317 && (type.equals(Library.SHARED) || type.equals(Library.JNI) || type.equals(Library.EXECUTABLE))) {
318 final LinkerArgument arg = new LinkerArgument();
319 if (isGenerateManifest())
320 arg.setValue("/MANIFEST");
321 else
322 arg.setValue("/MANIFEST:NO");
323 linker.addConfiguredLinkerArg(arg);
324
325 if (isGenerateManifest()) {
326 final LinkerArgument arg2 = new LinkerArgument();
327 arg2.setValue("/MANIFESTFILE:" + task.getOutfile() + ".manifest");
328 linker.addConfiguredLinkerArg(arg2);
329 }
330
331 }
332
333
334 if (this.options != null) {
335 for (final Object option : this.options) {
336 final LinkerArgument arg = new LinkerArgument();
337 arg.setValue((String) option);
338 linker.addConfiguredLinkerArg(arg);
339 }
340 }
341
342 if (this.optionSet != null) {
343
344 final String[] opts = this.optionSet.split("\\s");
345
346 for (final String opt : opts) {
347
348 final LinkerArgument arg = new LinkerArgument();
349
350 arg.setValue(opt);
351 linker.addConfiguredLinkerArg(arg);
352 }
353 }
354
355 if (!this.clearDefaultOptions) {
356 final String option = NarProperties.getInstance(mojo.getMavenProject()).getProperty(prefix + "options");
357 if (option != null) {
358 final String[] opt = option.split(" ");
359 for (final String element : opt) {
360 final LinkerArgument arg = new LinkerArgument();
361 arg.setValue(element);
362 linker.addConfiguredLinkerArg(arg);
363 }
364 }
365 }
366
367
368 if (this.narDependencyLibOrder != null) {
369
370 final List libOrder = new LinkedList();
371
372 final String[] lib = this.narDependencyLibOrder.split(",");
373
374 for (final String element : lib) {
375 libOrder.add(element.trim());
376 }
377
378 mojo.setDependencyLibOrder(libOrder);
379 }
380
381
382 if (this.libs != null || this.libSet != null) {
383
384 if (this.libs != null) {
385
386 for (final Object lib1 : this.libs) {
387
388 final Lib lib = (Lib) lib1;
389 lib.addLibSet(mojo, linker, antProject);
390 }
391 }
392
393 if (this.libSet != null) {
394 addLibraries(this.libSet, linker, antProject, false);
395 }
396 } else {
397
398 final String libsList = NarProperties.getInstance(mojo.getMavenProject()).getProperty(prefix + "libs");
399
400 addLibraries(libsList, linker, antProject, false);
401 }
402
403
404 if (this.sysLibs != null || this.sysLibSet != null) {
405
406 if (this.sysLibs != null) {
407
408 for (final Object sysLib1 : this.sysLibs) {
409
410 final SysLib sysLib = (SysLib) sysLib1;
411 linker.addSyslibset(sysLib.getSysLibSet(antProject));
412 }
413 }
414
415 if (this.sysLibSet != null) {
416 addLibraries(this.sysLibSet, linker, antProject, true);
417 }
418 } else {
419
420 final String sysLibsList = NarProperties.getInstance(mojo.getMavenProject()).getProperty(prefix + "sysLibs");
421
422 addLibraries(sysLibsList, linker, antProject, true);
423 }
424
425 mojo.getMsvc().configureLinker(linker);
426
427 return linker;
428 }
429
430 public final String getName() {
431 return this.name;
432 }
433
434 public final String getName(final NarProperties properties, final String prefix)
435 throws MojoFailureException, MojoExecutionException {
436 if (this.name == null && properties != null && prefix != null) {
437 this.name = properties.getProperty(prefix + "linker");
438 }
439 if (this.name == null) {
440 throw new MojoExecutionException("NAR: One of two things may be wrong here:\n\n"
441 + "1. <Name> tag is missing inside the <Linker> tag of your NAR configuration\n\n"
442 + "2. no linker is defined in the aol.properties file for '" + prefix + "linker'\n");
443 }
444 return this.name;
445 }
446
447
448
449
450
451 public final LinkerDef getTestLinker(final AbstractCompileMojo mojo, final CCTask task, final String os,
452 final String prefix, final String type) throws MojoFailureException, MojoExecutionException {
453 final LinkerDef linker = getLinker(mojo, task, os, prefix, type);
454 if (this.testOptions != null) {
455 for (final Object testOption : this.testOptions) {
456 final LinkerArgument arg = new LinkerArgument();
457 arg.setValue((String) testOption);
458 linker.addConfiguredLinkerArg(arg);
459 }
460 }
461 return linker;
462 }
463
464 public final String getVersion() throws MojoFailureException, MojoExecutionException {
465 return getVersion(new NarCompileMojo());
466 }
467
468 public final String getVersion(final AbstractNarMojo mojo) throws MojoFailureException, MojoExecutionException {
469 if (this.name == null) {
470 throw new MojoFailureException("Cannot deduce linker version if name is null");
471 }
472
473 String version = null;
474 String linkerPrefix = "";
475
476 if (this.prefix != null && (!this.prefix.isEmpty())) {
477 linkerPrefix = this.prefix;
478 }
479
480 final TextStream out = new StringTextStream();
481 final TextStream err = new StringTextStream();
482 final TextStream dbg = new StringTextStream();
483
484 if (this.name.equals("g++") || this.name.equals("gcc")) {
485 NarUtil.runCommand(linkerPrefix+"gcc", new String[] {
486 "--version"
487 }, null, null, out, err, dbg, this.log);
488 final Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+");
489 final Matcher m = p.matcher(out.toString());
490 if (m.find()) {
491 version = m.group(0);
492 }
493 } else if (this.name.equals("msvc")) {
494 version = mojo.getMsvc().getVersion();
495 } else if (this.name.equals("icc") || this.name.equals("icpc")) {
496 NarUtil.runCommand("icc", new String[] {
497 "--version"
498 }, null, null, out, err, dbg, this.log);
499 final Pattern p = Pattern.compile("\\d+\\.\\d+");
500 final Matcher m = p.matcher(out.toString());
501 if (m.find()) {
502 version = m.group(0);
503 }
504 } else if (this.name.equals("icl")) {
505 NarUtil.runCommand("icl", new String[] {
506 "/QV"
507 }, null, null, out, err, dbg, this.log);
508 final Pattern p = Pattern.compile("\\d+\\.\\d+");
509 final Matcher m = p.matcher(err.toString());
510 if (m.find()) {
511 version = m.group(0);
512 }
513 } else if (this.name.equals("CC")) {
514 NarUtil.runCommand("CC", new String[] {
515 "-V"
516 }, null, null, out, err, dbg, this.log);
517 final Pattern p = Pattern.compile("\\d+\\.d+");
518 final Matcher m = p.matcher(err.toString());
519 if (m.find()) {
520 version = m.group(0);
521 }
522 } else if (this.name.equals("xlC")) {
523 NarUtil.runCommand("/usr/vacpp/bin/xlC", new String[] {
524 "-qversion"
525 }, null, null, out, err, dbg, this.log);
526 final Pattern p = Pattern.compile("\\d+\\.\\d+");
527 final Matcher m = p.matcher(out.toString());
528 if (m.find()) {
529 version = m.group(0);
530 }
531 } else if (name.equals("clang") || name.equals("clang++")) {
532 NarUtil.runCommand("clang", new String[] {
533 "--version"
534 }, null, null, out, err, dbg, log);
535 final Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+");
536 final Matcher m = p.matcher(out.toString());
537 if (m.find()) {
538 version = m.group(0);
539 }
540 } else {
541 if (!this.prefix.isEmpty()) {
542 NarUtil.runCommand(linkerPrefix+this.name, new String[] {
543 "--version"
544 }, null, null, out, err, dbg, this.log);
545 final Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+");
546 final Matcher m = p.matcher(out.toString());
547 if (m.find()) {
548 version = m.group(0);
549 }
550 } else {
551 throw new MojoFailureException("Cannot find version number for linker '" + this.name + "'");
552 }
553 }
554
555 if (version == null) {
556 if (!err.toString().isEmpty())
557 mojo.getLog().debug("linker returned error stream: " + err.toString());
558 throw new MojoFailureException("Cannot deduce version number from: " + out.toString());
559 }
560 return version;
561 }
562 }