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.borland;
21
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29
30 import org.apache.tools.ant.BuildException;
31 import org.apache.xml.serialize.OutputFormat;
32 import org.apache.xml.serialize.Serializer;
33 import org.apache.xml.serialize.XMLSerializer;
34 import org.xml.sax.ContentHandler;
35 import org.xml.sax.SAXException;
36 import org.xml.sax.helpers.AttributesImpl;
37
38 import com.github.maven_nar.cpptasks.CCTask;
39 import com.github.maven_nar.cpptasks.CUtil;
40 import com.github.maven_nar.cpptasks.TargetInfo;
41 import com.github.maven_nar.cpptasks.compiler.CommandLineCompilerConfiguration;
42 import com.github.maven_nar.cpptasks.compiler.CommandLineLinkerConfiguration;
43 import com.github.maven_nar.cpptasks.compiler.ProcessorConfiguration;
44 import com.github.maven_nar.cpptasks.gcc.GccCCompiler;
45 import com.github.maven_nar.cpptasks.ide.ProjectDef;
46 import com.github.maven_nar.cpptasks.ide.ProjectWriter;
47
48
49
50
51
52
53
54 public final class CBuilderXProjectWriter implements ProjectWriter {
55
56
57
58 private static class PropertyWriter {
59
60
61
62 private final ContentHandler content;
63
64
65
66
67 private final AttributesImpl propertyAttributes;
68
69
70
71
72
73
74
75 public PropertyWriter(final ContentHandler contentHandler) {
76 this.content = contentHandler;
77 this.propertyAttributes = new AttributesImpl();
78 this.propertyAttributes.addAttribute(null, "category", "category", "#PCDATA", "");
79 this.propertyAttributes.addAttribute(null, "name", "name", "#PCDATA", "");
80 this.propertyAttributes.addAttribute(null, "value", "value", "#PCDATA", "");
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public final void write(final String category, final String name, final String value) throws SAXException {
96 this.propertyAttributes.setValue(0, category);
97 this.propertyAttributes.setValue(1, name);
98 this.propertyAttributes.setValue(2, value);
99 this.content.startElement(null, "property", "property", this.propertyAttributes);
100 this.content.endElement(null, "property", "property");
101 }
102 }
103
104
105
106
107 public CBuilderXProjectWriter() {
108 }
109
110
111
112
113
114
115
116
117 private String getActivePlatform(final CCTask task) {
118 final String osName = System.getProperty("os.name").toLowerCase(Locale.US);
119 if (osName.contains("windows")) {
120 return "win32";
121 }
122 return "linux";
123 }
124
125
126
127
128
129
130
131
132
133 private CommandLineCompilerConfiguration getBaseCompilerConfiguration(final Map<String, TargetInfo> targets) {
134
135
136
137 CommandLineCompilerConfiguration compilerConfig = null;
138
139
140
141 for (final TargetInfo targetInfo : targets.values()) {
142 final ProcessorConfiguration config = targetInfo.getConfiguration();
143 final String identifier = config.getIdentifier();
144
145
146
147 if (config instanceof CommandLineCompilerConfiguration) {
148 compilerConfig = (CommandLineCompilerConfiguration) config;
149 if (compilerConfig.getCompiler() instanceof GccCCompiler || compilerConfig
150 .getCompiler() instanceof BorlandCCompiler) {
151 return compilerConfig;
152 }
153 }
154 }
155 return null;
156 }
157
158
159
160
161
162
163
164
165 private String getBuildType(final CCTask task) {
166 final String outType = task.getOuttype();
167 if ("executable".equals(outType)) {
168 return "exeproject";
169 } else if ("static".equals(outType)) {
170 return "libraryproject";
171 }
172 return "dllproject";
173 }
174
175 private String getWin32Toolset(final CommandLineCompilerConfiguration compilerConfig) {
176 if (compilerConfig != null && compilerConfig.getCompiler() instanceof BorlandCCompiler) {
177 return "win32b";
178 }
179 return "MinGW";
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194 private void writeCompileOptions(final String baseDir, final PropertyWriter writer,
195 final CommandLineCompilerConfiguration compilerConfig) throws SAXException {
196 boolean isBcc = false;
197 boolean isUnix = true;
198 String compileID = "linux.Debug_Build.gnuc++.g++compile";
199 if (compilerConfig.getCompiler() instanceof BorlandCCompiler) {
200 compileID = "win32.Debug_Build.win32b.bcc32";
201 isUnix = false;
202 isBcc = true;
203 }
204
205 final File[] includePath = compilerConfig.getIncludePath();
206 int includeIndex = 1;
207 if (isUnix) {
208 writer.write(compileID, "option.I.arg." + includeIndex++, "/usr/include");
209 writer.write(compileID, "option.I.arg." + includeIndex++, "/usr/include/g++-3");
210 }
211 for (final File element : includePath) {
212 final String relPath = CUtil.getRelativePath(baseDir, element);
213 writer.write(compileID, "option.I.arg." + includeIndex++, relPath);
214 }
215 if (includePath.length > 0) {
216 writer.write(compileID, "option.I.enabled", "1");
217 }
218
219 String defineBase = "option.D_MACRO_VALUE";
220 if (isBcc) {
221 defineBase = "option.D";
222 }
223 final String defineOption = defineBase + ".arg.";
224 int defineIndex = 1;
225 int undefineIndex = 1;
226 final String[] preArgs = compilerConfig.getPreArguments();
227 for (final String preArg : preArgs) {
228 if (preArg.startsWith("-D")) {
229 writer.write(compileID, defineOption + defineIndex++, preArg.substring(2));
230 } else if (preArg.startsWith("-U")) {
231 writer.write(compileID, "option.U.arg." + undefineIndex++, preArg.substring(2));
232 } else if (!(preArg.startsWith("-I") || preArg.startsWith("-o"))) {
233
234
235
236 writer.write(compileID, "option." + preArg.substring(1) + ".enabled", "1");
237 }
238 }
239 if (defineIndex > 1) {
240 writer.write(compileID, defineBase + ".enabled", "1");
241 }
242 if (undefineIndex > 1) {
243 writer.write(compileID, "option.U.enabled", "1");
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258
259 private void writeIlinkArgs(final PropertyWriter writer, final String linkID, final String[] args)
260 throws SAXException {
261 for (final String arg : args) {
262 if (arg.charAt(0) == '/' || arg.charAt(0) == '-') {
263 final int equalsPos = arg.indexOf('=');
264 if (equalsPos > 0) {
265 final String option = "option." + arg.substring(0, equalsPos - 1);
266 writer.write(linkID, option + ".enabled", "1");
267 writer.write(linkID, option + ".value", arg.substring(equalsPos + 1));
268 } else {
269 writer.write(linkID, "option." + arg.substring(1) + ".enabled", "1");
270 }
271 }
272 }
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287 private void writeLdArgs(final PropertyWriter writer, final String linkID, final String[] preArgs)
288 throws SAXException {
289 int objnameIndex = 1;
290 int libnameIndex = 1;
291 int libpathIndex = 1;
292 for (final String preArg : preArgs) {
293 if (preArg.startsWith("-o")) {
294 writer.write(linkID, "option.o.arg." + objnameIndex++, preArg.substring(2));
295 } else if (preArg.startsWith("-l")) {
296 writer.write(linkID, "option.l.arg." + libnameIndex++, preArg.substring(2));
297 } else if (preArg.startsWith("-L")) {
298 writer.write(linkID, "option.L.arg." + libpathIndex++, preArg.substring(2));
299 } else {
300
301
302
303 writer.write(linkID, "option." + preArg.substring(1) + ".enabled", "1");
304 }
305 }
306 if (objnameIndex > 1) {
307 writer.write(linkID, "option.o.enabled", "1");
308 }
309 if (libnameIndex > 1) {
310 writer.write(linkID, "option.l.enabled", "1");
311 }
312 if (libpathIndex > 1) {
313 writer.write(linkID, "option.L.enabled", "1");
314 }
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328
329 private void writeLinkOptions(final String baseDir, final PropertyWriter writer, final TargetInfo linkTarget)
330 throws SAXException {
331 if (linkTarget != null) {
332 final ProcessorConfiguration config = linkTarget.getConfiguration();
333 if (config instanceof CommandLineLinkerConfiguration) {
334 final CommandLineLinkerConfiguration linkConfig = (CommandLineLinkerConfiguration) config;
335
336 if (linkConfig.getLinker() instanceof BorlandLinker) {
337 final String linkID = "win32.Debug_Build.win32b.ilink32";
338 writeIlinkArgs(writer, linkID, linkConfig.getPreArguments());
339 writeIlinkArgs(writer, linkID, linkConfig.getEndArguments());
340 writer.write(linkID, "param.libfiles.1", "cw32mt.lib");
341 writer.write(linkID, "param.libfiles.2", "import32.lib");
342 int libIndex = 3;
343 final String[] libNames = linkConfig.getLibraryNames();
344 for (final String libName : libNames) {
345 writer.write(linkID, "param.libfiles." + libIndex++, libName);
346 }
347 final String startup = linkConfig.getStartupObject();
348 if (startup != null) {
349 writer.write(linkID, "param.objfiles.1", startup);
350 }
351 } else {
352 final String linkID = "linux.Debug_Build.gnuc++.g++link";
353 writeLdArgs(writer, linkID, linkConfig.getPreArguments());
354 writeLdArgs(writer, linkID, linkConfig.getEndArguments());
355 }
356 }
357 }
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380 @Override
381 public void writeProject(final File fileName, final CCTask task, final ProjectDef projectDef,
382 final List<File> sources, final Map<String, TargetInfo> targets, final TargetInfo linkTarget)
383 throws IOException, SAXException {
384
385 String projectName = projectDef.getName();
386 if (projectName == null) {
387 projectName = fileName.getName();
388 }
389 final String basePath = fileName.getAbsoluteFile().getParent();
390
391 final File projectFile = new File(fileName + ".cbx");
392 if (!projectDef.getOverwrite() && projectFile.exists()) {
393 throw new BuildException("Not allowed to overwrite project file " + projectFile.toString());
394 }
395
396 final CommandLineCompilerConfiguration compilerConfig = getBaseCompilerConfiguration(targets);
397 if (compilerConfig == null) {
398 throw new BuildException("Unable to generate C++ BuilderX project when gcc or bcc is not used.");
399 }
400
401 final OutputStream outStream = new FileOutputStream(projectFile);
402 final OutputFormat format = new OutputFormat("xml", "UTF-8", true);
403 final Serializer serializer = new XMLSerializer(outStream, format);
404 final ContentHandler content = serializer.asContentHandler();
405 content.startDocument();
406 final AttributesImpl emptyAttrs = new AttributesImpl();
407 content.startElement(null, "project", "project", emptyAttrs);
408 final PropertyWriter propertyWriter = new PropertyWriter(content);
409 propertyWriter.write("build.config", "active", "0");
410 propertyWriter.write("build.config", "count", "0");
411 propertyWriter.write("build.config", "excludedefaultforzero", "0");
412 propertyWriter.write("build.config.0", "builddir", "Debug");
413 propertyWriter.write("build.config.0", "key", "Debug_Build");
414 propertyWriter.write("build.config.0", "linux.builddir", "linux/Debug_Build");
415 propertyWriter.write("build.config.0", "settings.MinGW", "default;debug");
416 propertyWriter.write("build.config.0", "settings.gnuc++", "default;debug");
417 propertyWriter.write("build.config.0", "settings.intellinia32", "default;debug");
418 propertyWriter.write("build.config.0", "settings.mswin32", "default;debug");
419 propertyWriter.write("build.config.0", "type", "Toolset");
420 propertyWriter.write("build.config.0", "win32.builddir", "windows/Debug_Build");
421 propertyWriter.write("build.node", "name", projectDef.getName());
422 final String buildType = getBuildType(task);
423 propertyWriter.write("build.node", "type", buildType);
424 propertyWriter.write("build.platform", "active", getActivePlatform(task));
425 propertyWriter.write("build.platform", "linux.Debug_Build.toolset", "gnuc++");
426 propertyWriter.write("build.platform", "linux.Release_Build.toolset", "gnuc++");
427 propertyWriter.write("build.platform", "linux.default", "gnuc++");
428 propertyWriter.write("build.platform", "linux.gnuc++.enabled", "1");
429 propertyWriter.write("build.platform", "linux.mswin32.enabled", "1");
430 propertyWriter.write("build.platform", "linux.win32b.enabled", "1");
431 propertyWriter.write("build.platform", "solaris.default", "gnuc++");
432 propertyWriter.write("build.platform", "solaris.enabled", "1");
433 final String toolset = getWin32Toolset(compilerConfig);
434 propertyWriter.write("build.platform", "win32.default", toolset);
435 propertyWriter.write("build.platform", "win32." + toolset + ".enabled", "1");
436
437 propertyWriter.write("cbproject", "version", "X.1.0");
438 if ("dllproject".equals(buildType)) {
439 propertyWriter.write("gnuc++.g++compile", "option.fpic_using_GOT.enabled", "1");
440 propertyWriter.write("gnuc++.g++link", "option.shared.enabled", "1");
441 propertyWriter.write("intellinia32.icc", "option.minus_Kpic.enabled", "1");
442 propertyWriter.write("intellinia32.icclink", "option.minus_shared.enabled", "1");
443 }
444
445
446
447 writeCompileOptions(basePath, propertyWriter, compilerConfig);
448 writeLinkOptions(basePath, propertyWriter, linkTarget);
449 propertyWriter.write("linux.gnuc++.Debug_Build", "saved", "1");
450 if ("dllproject".equals(buildType)) {
451 propertyWriter.write("runtime", "ExcludeDefaultForZero", "1");
452
453 } else if ("exeproject".equals(buildType)) {
454 propertyWriter.write("runtime.0", "BuildTargetOnRun", "com.borland.cbuilder.build."
455 + "CBProjectBuilder$ProjectBuildAction;make");
456 propertyWriter.write("runtime.0", "ConfigurationName", projectDef.getName());
457 propertyWriter.write("runtime.0", "RunnableType", "com.borland.cbuilder.runtime.ExecutableRunner");
458 }
459 final AttributesImpl fileAttributes = new AttributesImpl();
460 fileAttributes.addAttribute(null, "path", "path", "#PCDATA", "");
461 AttributesImpl gccAttributes = null;
462 if (!"g++".equals(compilerConfig.getCommand())) {
463 gccAttributes = new AttributesImpl();
464 gccAttributes.addAttribute(null, "category", "category", "#PCDATA", "build.basecmd");
465 gccAttributes.addAttribute(null, "name", "name", "#PCDATA", "linux.gnuc++.Debug_Build.g++_key");
466 gccAttributes.addAttribute(null, "value", "value", "#PCDATA", compilerConfig.getCommand());
467 }
468
469 for (final TargetInfo info : targets.values()) {
470 final File[] targetsources = info.getSources();
471 for (final File targetsource : targetsources) {
472 final String relativePath = CUtil.getRelativePath(basePath, targetsource);
473 fileAttributes.setValue(0, relativePath);
474 content.startElement(null, "file", "file", fileAttributes);
475
476
477
478
479 if (gccAttributes != null) {
480 content.startElement(null, "property", "property", gccAttributes);
481 content.endElement(null, "property", "property");
482 }
483 content.endElement(null, "file", "file");
484 }
485 }
486 content.endElement(null, "project", "project");
487 content.endDocument();
488 }
489
490 }