View Javadoc
1   package org.codehaus.mojo.natives.c;
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  
27  import java.io.File;
28  import java.io.FileWriter;
29  import java.io.IOException;
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import org.codehaus.mojo.natives.NativeBuildException;
34  import org.codehaus.mojo.natives.linker.AbstractLinker;
35  import org.codehaus.mojo.natives.linker.Linker;
36  import org.codehaus.mojo.natives.linker.LinkerConfiguration;
37  import org.codehaus.mojo.natives.util.FileUtil;
38  import org.codehaus.plexus.component.annotations.Component;
39  import org.codehaus.plexus.util.FileUtils;
40  import org.codehaus.plexus.util.cli.Commandline;
41  
42  /**
43   * Generic C/CPP linker with "-o " as its output option
44   */
45  @Component(role = Linker.class, hint = "generic", instantiationStrategy = "per-lookup")
46  public class CLinker
47      extends AbstractLinker
48  {
49  
50      /**
51       * @return Commandline of a linker base on its configuration and object files
52       */
53      protected Commandline createLinkerCommandLine( List objectFiles, LinkerConfiguration config )
54          throws NativeBuildException
55      {
56          if ( config.getExecutable() == null )
57          {
58              config.setExecutable( "gcc" );
59          }
60  
61          Commandline cl = new Commandline();
62  
63          cl.setWorkingDirectory( config.getWorkingDirectory().getPath() );
64  
65          cl.setExecutable( config.getExecutable() );
66  
67          if ( config.getStartOptions() != null )
68          {
69              cl.addArguments( config.getStartOptions() );
70          }
71  
72          String linkerOutputOption = this.getLinkerOutputOption();
73          if ( linkerOutputOption.endsWith( " " ) )
74          {
75              cl.createArg().setValue( linkerOutputOption.substring( 0, linkerOutputOption.length() - 1 ) );
76              cl.createArg().setFile( config.getOutputFile() );
77          }
78          else
79          {
80              cl.createArg().setValue( linkerOutputOption + config.getOutputFile() );
81          }
82  
83          // On windows to avoid command lines too long we have to use a linker response file.
84          if ( config.isUsingLinkerResponseFile() )
85          {
86              try
87              {
88                  File linkerFile = new File( config.getWorkingDirectory(), "objectsFile" );
89                  FileWriter linkerFileWriter = new FileWriter( linkerFile, false /* Don't append */);
90                  for ( int i = 0; i < objectFiles.size(); ++i )
91                  {
92                      File objFile = (File) objectFiles.get( i );
93                      linkerFileWriter.write( objFile.getPath() + "\n" );
94                  }
95                  linkerFileWriter.close();
96              }
97              catch ( IOException error )
98              {
99                  throw new NativeBuildException( "Error creating linker response file", error );
100             }
101 
102             cl.createArg().setValue( "@objectsFile" );
103         }
104         else
105         { // Normal behavior.
106 
107             for ( int i = 0; i < objectFiles.size(); ++i )
108             {
109                 File objFile = (File) objectFiles.get( i );
110 
111                 // we need to shorten the command line since windows has limited command line length
112                 String objFilePath = FileUtil.truncatePath( objFile.getPath(), config.getWorkingDirectory().getPath() );
113 
114                 cl.createArg().setValue( objFilePath );
115             }
116         }
117 
118         if ( config.getMiddleOptions() != null )
119         {
120             cl.addArguments( config.getMiddleOptions() );
121         }
122 
123         setCommandLineForExternalLibraries( cl, config );
124 
125         if ( config.getEndOptions() != null )
126         {
127             cl.addArguments( config.getEndOptions() );
128         }
129 
130         return cl;
131 
132     }
133 
134     /**
135      * @return output option flag of a generic C linker
136      */
137     protected String getLinkerOutputOption()
138     {
139         return "-o ";
140     }
141 
142     /**
143      * Setup Commandline to handle external library depending on extention type
144      * 
145      * @param cl Commandline
146      * @param config LinkerConfiguration
147      * @throws NativeBuildException
148      */
149     protected void setCommandLineForExternalLibraries( Commandline cl, LinkerConfiguration config )
150         throws NativeBuildException
151     {
152         if ( config.getExternalLibFileNames().size() == 0 )
153         {
154             return;
155         }
156 
157         boolean hasUnixLinkage = false;
158 
159         for ( Iterator iter = config.getExternalLibFileNames().iterator(); iter.hasNext(); )
160         {
161             String libFileName = (String) iter.next();
162 
163             String ext = FileUtils.getExtension( libFileName );
164 
165             if ( "o".equals( ext ) || "obj".equals( ext ) || "lib".equals( ext ) || "dylib".equals( ext ) )
166             {
167                 File libFile = new File( config.getExternalLibDirectory(), libFileName );
168                 String relativeLibFile =
169                     FileUtil.truncatePath( libFile.getPath(), config.getWorkingDirectory().getPath() );
170                 cl.createArg().setValue( relativeLibFile );
171             }
172             else if ( "a".equals( ext ) || "so".equals( ext ) || "sl".equals( ext ) )
173             {
174                 hasUnixLinkage = true;
175             }
176         }
177 
178         if ( hasUnixLinkage )
179         {
180             cl.createArg().setValue( "-L" + config.getExternalLibDirectory() );
181         }
182 
183         for ( Iterator iter = config.getExternalLibFileNames().iterator(); iter.hasNext(); )
184         {
185             String libFileName = (String) iter.next();
186 
187             String ext = FileUtils.getExtension( libFileName );
188 
189             if ( "a".equals( ext ) || "so".equals( ext ) || "sl".equals( ext ) )
190             {
191                 String libName = FileUtils.removeExtension( libFileName );
192 
193                 if ( libFileName.startsWith( "lib" ) )
194                 {
195                     libName = libName.substring( "lib".length() );
196                 }
197 
198                 cl.createArg().setValue( "-l" + libName );
199             }
200         }
201     }
202 
203 }