View Javadoc
1   package org.codehaus.mojo.natives.mingw;
2   
3   /*
4    * The MIT License
5    *
6    * Copyright (c) 2004, The Codehaus
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   * 
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   * 
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   */
26  import java.io.File;
27  import java.io.FileWriter;
28  import java.io.IOException;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import org.codehaus.mojo.natives.NativeBuildException;
33  import org.codehaus.mojo.natives.linker.AbstractLinker;
34  import org.codehaus.mojo.natives.linker.Linker;
35  import org.codehaus.mojo.natives.linker.LinkerConfiguration;
36  import org.codehaus.mojo.natives.util.FileUtil;
37  import org.codehaus.plexus.component.annotations.Component;
38  import org.codehaus.plexus.util.FileUtils;
39  import org.codehaus.plexus.util.cli.Commandline;
40  
41  /**
42   * Generic MinGW linker with "-o " as its output option
43   */
44  @Component(role = Linker.class, hint = "mingw", instantiationStrategy = "per-lookup")
45  public final class GccLinker extends AbstractLinker {
46  
47      /**
48       * @return Commandline of a linker base on its configuration and object
49       * files
50       */
51      protected Commandline createLinkerCommandLine(List objectFiles, LinkerConfiguration config)
52              throws NativeBuildException {
53          if (config.getExecutable() == null) {
54              config.setExecutable("gcc");
55          }
56  
57          Commandline cl = new Commandline();
58  
59          cl.setWorkingDirectory(config.getWorkingDirectory().getPath());
60  
61          cl.setExecutable(config.getExecutable());
62  
63          if (config.getStartOptions() != null) {
64              cl.addArguments(config.getStartOptions());
65          }
66  
67          String linkerOutputOption = this.getLinkerOutputOption();
68          if (linkerOutputOption.endsWith(" ")) {
69              cl.createArg().setValue(linkerOutputOption.substring(0, linkerOutputOption.length() - 1));
70              cl.createArg().setFile(config.getOutputFile());
71          } else {
72              cl.createArg().setValue(linkerOutputOption + config.getOutputFile());
73          }
74  
75          // On windows to avoid command lines too long we have to use a linker response file.
76          if (config.isUsingLinkerResponseFile()) {
77              try {
78                  File linkerFile = new File(config.getWorkingDirectory(), "objectsFile");
79                  FileWriter linkerFileWriter = new FileWriter(linkerFile, false /* Don't append */);
80                  for (int i = 0; i < objectFiles.size(); ++i) {
81                      File objFile = (File) objectFiles.get(i);
82                      linkerFileWriter.write(objFile.getPath() + "\n");
83                  }
84                  linkerFileWriter.close();
85              }
86              catch (IOException error) {
87                  throw new NativeBuildException("Error creating linker response file", error);
88              }
89  
90              cl.createArg().setValue("@objectsFile");
91          } else { // Normal behavior.
92  
93              for (int i = 0; i < objectFiles.size(); ++i) {
94                  File objFile = (File) objectFiles.get(i);
95  
96                  // we need to shorten the command line since windows has limited command line length
97                  String objFilePath = FileUtil.truncatePath(objFile.getPath(), config.getWorkingDirectory().getPath());
98  
99                  cl.createArg().setValue(objFilePath);
100             }
101         }
102 
103         if (config.getMiddleOptions() != null) {
104             cl.addArguments(config.getMiddleOptions());
105         }
106 
107         setCommandLineForExternalLibraries(cl, config);
108 
109         if (config.getEndOptions() != null) {
110             cl.addArguments(config.getEndOptions());
111         }
112 
113         return cl;
114 
115     }
116 
117     /**
118      * @return output option flag of a generic C linker
119      */
120     protected String getLinkerOutputOption() {
121         return "-o ";
122     }
123 
124     /**
125      * Setup Commandline to handle external library depending on extention type
126      *
127      * @param cl Commandline
128      * @param config LinkerConfiguration
129      * @throws NativeBuildException
130      */
131     protected void setCommandLineForExternalLibraries(Commandline cl, LinkerConfiguration config)
132             throws NativeBuildException {
133         if (config.getExternalLibFileNames().size() == 0) {
134             return;
135         }
136 
137         boolean hasUnixLinkage = false;
138 
139         for (Iterator iter = config.getExternalLibFileNames().iterator(); iter.hasNext();) {
140             String libFileName = (String) iter.next();
141 
142             String ext = FileUtils.getExtension(libFileName);
143 
144             if ("o".equals(ext) || "obj".equals(ext) || "lib".equals(ext) || "dylib".equals(ext)) {
145                 File libFile = new File(config.getExternalLibDirectory(), libFileName);
146                 String relativeLibFile
147                         = FileUtil.truncatePath(libFile.getPath(), config.getWorkingDirectory().getPath());
148                 cl.createArg().setValue(relativeLibFile);
149             } else if ("a".equals(ext) || "so".equals(ext) || "sl".equals(ext)) {
150                 hasUnixLinkage = true;
151             }
152         }
153 
154         if (hasUnixLinkage) {
155             cl.createArg().setValue("-L" + config.getExternalLibDirectory());
156         }
157 
158         for (Iterator iter = config.getExternalLibFileNames().iterator(); iter.hasNext();) {
159             String libFileName = (String) iter.next();
160 
161             String ext = FileUtils.getExtension(libFileName);
162 
163             if ("a".equals(ext) || "so".equals(ext) || "sl".equals(ext)) {
164                 String libName = FileUtils.removeExtension(libFileName);
165 
166                 if (libFileName.startsWith("lib")) {
167                     libName = libName.substring("lib".length());
168                 }
169 
170                 cl.createArg().setValue("-l" + libName);
171             }
172         }
173     }
174 
175 }