source: rtems-tools/rtemstoolkit/rld-cc.cpp @ 0c0b2d4

4.10
Last change on this file since 0c0b2d4 was 53e387d, checked in by Chris Johns <chrisj@…>, on Nov 4, 2014 at 8:39:57 AM

linkers: Merge the standard libraries into the user library paths.

The change to rld::split clears the user's library paths. Fix
this.

  • Property mode set to 100644
File size: 16.2 KB
Line 
1/*
2 * Copyright (c) 2011-2014, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <string.h>
18
19#include <fstream>
20
21#include <rld.h>
22#include <rld-cc.h>
23#include <rld-process.h>
24#include <rld-rtems.h>
25
26namespace rld
27{
28  namespace cc
29  {
30    static std::string cc;              //< The CC executable as absolute path.
31    static bool        cc_set;          //< True when the CC has been set.
32    static std::string cc_name = "gcc"; //< The CC name, ie gcc, clang.
33
34    static std::string ld;              //< The LD executable as absolute path.
35    static bool        ld_set;          //< True when the LD has been set.
36    static std::string ld_name = "gcc"; //< The LD name, ie gcc, clang.
37
38    static std::string exec_prefix;     //< The CC/LD executable prefix.
39
40    static std::string cppflags;        //< The CPP flags.
41    static std::string cflags;          //< The CC flags.
42    static std::string cxxflags;        //< The CXX flags.
43    static std::string ldflags;         //< The LD flags.
44
45    static std::string warning_cflags;  //< The warning flags in cflags.
46    static std::string include_cflags;  //< The include flags in cflags.
47    static std::string machine_cflags;  //< The machine flags in cflags.
48    static std::string spec_cflags;     //< The spec flags in cflags.
49
50    static std::string install_path;    //< The CC reported install path.
51    static std::string programs_path;   //< The CC reported programs path.
52    static std::string libraries_path;  //< The CC reported libraries path.
53
54    /**
55     * The list of standard libraries.
56     */
57    #define RPS RLD_PATHSTR_SEPARATOR_STR
58    static const char* std_lib_c         = "libgcc.a" RPS "libssp.a" RPS "libc.a";
59    static const char* std_lib_cplusplus = "libstdc++.a";
60
61    const std::string
62    strip_cflags (const std::string& flags)
63    {
64      std::string  oflags;
65      rld::strings flags_;
66      rld::split (flags_, flags);
67
68      for (rld::strings::iterator si = flags_.begin ();
69           si != flags_.end ();
70           ++si)
71      {
72        if (!rld::starts_with ((*si), "-O") && !rld::starts_with ((*si), "-g"))
73          oflags += ' ' + *si;
74      }
75
76      return rld::trim (oflags);
77    }
78
79    const std::string
80    filter_flags (const std::string& flags,
81                  const std::string& ,
82                  const std::string& ,
83                  flag_type          type,
84                  std::string&       warnings,
85                  std::string&       includes,
86                  std::string&       machines,
87                  std::string&       specs)
88    {
89      /*
90       * Defintion of flags to be filtered.
91       */
92      enum flag_group
93      {
94        fg_warning,
95        fg_include,
96        fg_machine,
97        fg_specs
98      };
99      struct flag_def
100      {
101        flag_group  group;  ///< The group this flag belong to.
102        const char* opt;    ///< Option start.
103        int         count;  ///< Number of arguments with the option.
104        bool        path;   ///< Is this a path ?
105        int         out;    ///< If the flag type is set drop the opt..
106      };
107      const flag_def flag_defs[] =
108        {
109          { fg_warning, "-W",       1, false, ft_cppflags | ft_cflags | ft_ldflags },
110          { fg_include, "-I",       2, true,  0 },
111          { fg_include, "-isystem", 2, true,  0 },
112          { fg_include, "-sysroot", 2, true,  0 },
113          { fg_machine, "-O",       1, false, 0 },
114          { fg_machine, "-m",       1, false, 0 },
115          { fg_machine, "-f",       1, false, 0 },
116          { fg_specs,   "-q",       1, false, 0 },
117          { fg_specs,   "-B",       2, true,  0 },
118          { fg_specs,   "--specs",  2, false, 0 }
119        };
120      const int flag_def_size = sizeof (flag_defs) / sizeof (flag_def);
121
122      std::string  oflags;
123      rld::strings flags_;
124
125      rld::split (flags_, strip_cflags (flags));
126
127      warnings.clear ();
128      includes.clear ();
129      machines.clear ();
130      specs.clear ();
131
132      for (rld::strings::iterator si = flags_.begin ();
133           si != flags_.end ();
134           ++si)
135      {
136        std::string  opts;
137        std::string& opt = *(si);
138        bool         in = true;
139
140        for (int fd = 0; fd < flag_def_size; ++fd)
141        {
142          if (rld::starts_with (opt, flag_defs[fd].opt))
143          {
144            int opt_count = flag_defs[fd].count;
145            if (opt_count > 1)
146            {
147              /*
148               * See if the flag is just the option. If is not take one less
149               * because the option's argument is joined to the option.
150               */
151              if (opt != flag_defs[fd].opt)
152              {
153                opt_count -= 1;
154                /*
155                 * @todo Path processing here. Not sure what it is needed for.
156                 */
157              }
158            }
159            opts += ' ' + opt;
160            while (opt_count > 1)
161            {
162              ++si;
163              /*
164               * @todo Path processing here. Not sure what it is needed for.
165               */
166              opts += ' ' + (*si);
167              --opt_count;
168            }
169            switch (flag_defs[fd].group)
170            {
171              case fg_warning:
172                warnings += ' ' + opts;
173                break;
174              case fg_include:
175                includes += ' ' + opts;
176                break;
177              case fg_machine:
178                machines += ' ' + opts;
179                break;
180              case fg_specs:
181                specs += ' ' + opts;
182                break;
183              default:
184                throw rld::error ("Invalid group", "flag group");
185            }
186            if ((flag_defs[fd].out & type) != 0)
187              in = false;
188            break;
189          }
190        }
191
192        if (in)
193          oflags += ' ' + opts;
194      }
195
196      rld::trim (warnings);
197      rld::trim (includes);
198      rld::trim (machines);
199      rld::trim (specs);
200
201      return rld::trim (oflags);
202    }
203
204    const std::string
205    filter_flags (const std::string& flags,
206                  const std::string& arch,
207                  const std::string& path,
208                  flag_type          type)
209    {
210      if (type != ft_cflags)
211      {
212        std::string warnings;
213        std::string includes;
214        std::string machines;
215        std::string specs;
216        return filter_flags (flags,
217                             arch,
218                             path,
219                             type,
220                             warnings,
221                             includes,
222                             machines,
223                             specs);
224      }
225      else
226      {
227        return filter_flags (flags,
228                             arch,
229                             path,
230                             type,
231                             warning_cflags,
232                             include_cflags,
233                             machine_cflags,
234                             spec_cflags);
235      }
236    }
237
238    void
239    set_cc (const std::string& cc_)
240    {
241      cc = cc_;
242      cc_set = true;
243    }
244
245    const std::string
246    get_cc ()
247    {
248      return cc;
249    }
250
251    bool
252    is_cc_set ()
253    {
254      return cc_set;
255    }
256
257    void
258    set_ld (const std::string& ld_)
259    {
260      ld = ld_;
261      ld_set = true;
262    }
263
264    const std::string
265    get_ld ()
266    {
267      return ld;
268    }
269
270    bool
271    is_ld_set ()
272    {
273      return ld_set;
274    }
275
276    void
277    set_exec_prefix (const std::string& exec_prefix_)
278    {
279      exec_prefix = exec_prefix_;
280    }
281
282    const std::string
283    get_exec_prefix ()
284    {
285      return exec_prefix;
286    }
287
288    bool
289    is_exec_prefix_set ()
290    {
291      return !exec_prefix.empty ();
292    }
293
294    void
295    set_flags (const std::string& flags,
296               const std::string& arch,
297               const std::string& path,
298               flag_type          type)
299    {
300      std::string* oflags;
301      switch (type)
302      {
303        case ft_cppflags:
304          oflags = &cppflags;
305          break;
306        case ft_cflags:
307          oflags = &cflags;
308          break;
309        case ft_cxxflags:
310          oflags = &cxxflags;
311          break;
312        case ft_ldflags:
313          oflags = &ldflags;
314          break;
315        default:
316          throw rld::error ("Invalid flag type", "CC set flags");
317      }
318      (*oflags) = filter_flags (flags, arch, path, type);
319    }
320
321    void
322    set_flags (const std::string& flags, flag_type type)
323    {
324      std::string arch;
325      std::string path;
326      set_flags (flags, arch, path, type);
327    }
328
329    void
330    append_flags (const std::string& flags,
331                  const std::string& arch,
332                  const std::string& path,
333                  flag_type          type)
334    {
335      std::string* oflags;
336      switch (type)
337      {
338        case ft_cppflags:
339          oflags = &cppflags;
340          break;
341        case ft_cflags:
342          oflags = &cflags;
343          break;
344        case ft_cxxflags:
345          oflags = &cxxflags;
346          break;
347        case ft_ldflags:
348          oflags = &ldflags;
349          break;
350        default:
351          throw rld::error ("Invalid flag type", "CC set flags");
352      }
353      if (oflags->empty ())
354        *oflags += filter_flags (flags, arch, path, type);
355      else
356        *oflags += ' ' + filter_flags (flags, arch, path, type);
357    }
358
359    void
360    append_flags (const std::string& flags, flag_type type)
361    {
362      std::string arch;
363      std::string path;
364      append_flags (flags, arch, path, type);
365    }
366
367    const std::string
368    get_flags (flag_type type)
369    {
370      std::string* flags;
371      switch (type)
372      {
373        case ft_cppflags:
374          flags = &cppflags;
375          break;
376        case ft_cflags:
377          flags = &cflags;
378          break;
379        case ft_cxxflags:
380          flags = &cxxflags;
381          break;
382        case ft_ldflags:
383          flags = &ldflags;
384          break;
385        default:
386          throw rld::error ("Invalid flag type", "CC get flags");
387      }
388      return *flags;
389    }
390
391    const std::string
392    get_flags (flag_group group)
393    {
394      std::string* flags;
395      switch (group)
396      {
397        case fg_warning_flags:
398          flags = &warning_cflags;
399          break;
400        case fg_include_flags:
401          flags = &include_cflags;
402          break;
403        case fg_machine_flags:
404          flags = &machine_cflags;
405          break;
406        case fg_spec_flags:
407          flags = &spec_cflags;
408          break;
409        default:
410          throw rld::error ("Invalid flag group", "CC get flags");
411      }
412      return *flags;
413    }
414
415    void
416    append_flags (flag_type type, rld::process::arg_container& args)
417    {
418      const std::string* flags = 0;
419      switch (type)
420      {
421        case ft_cppflags:
422          flags = &cppflags;
423          break;
424        case ft_cflags:
425          flags = &cflags;
426          break;
427        case ft_cxxflags:
428          flags = &cxxflags;
429          break;
430        case ft_ldflags:
431          flags = &ldflags;
432          break;
433        default:
434          throw rld::error ("Invalid flag type", "CC append flags");
435      }
436      if (!flags->empty ())
437        rld::process::args_append (args, *flags);
438    }
439
440    void
441    make_cc_command (rld::process::arg_container& args)
442    {
443      /*
444       * Use the absolute path to CC if provided.
445       */
446      if (is_cc_set ())
447      {
448        args.push_back (cc);
449      }
450      else
451      {
452        std::string cmd = cc_name;
453        if (!exec_prefix.empty ())
454          cmd = exec_prefix + "-rtems" + rld::rtems::version () + '-' + cmd;
455        args.push_back (cmd);
456      }
457    }
458
459    void
460    make_ld_command (rld::process::arg_container& args)
461    {
462      /*
463       * Use the absolute path to LD if provided.
464       */
465      if (is_ld_set ())
466      {
467        args.push_back (get_ld ());
468      }
469      else
470      {
471        std::string cmd = ld_name;
472        if (!exec_prefix.empty ())
473          cmd = exec_prefix + "-rtems" + rld::rtems::version () + '-' + cmd;
474        args.push_back (cmd);
475      }
476    }
477
478    static bool
479    match_and_trim (const char* prefix, std::string& line, std::string& result)
480    {
481      std::string::size_type pos = ::strlen (prefix);
482      if (line.substr (0, pos) == prefix)
483      {
484        if (line[pos] == '=')
485          ++pos;
486        result = line.substr (pos, line.size () - pos - 1);
487        return true;
488      }
489      return false;
490    }
491
492    static void
493    search_dirs ()
494    {
495      rld::process::arg_container args;
496
497      make_cc_command (args);
498      append_flags (ft_cppflags, args);
499      append_flags (ft_cflags, args);
500      args.push_back ("-print-search-dirs");
501
502      rld::process::tempfile out;
503      rld::process::tempfile err;
504      rld::process::status   status;
505
506      status = rld::process::execute (cc_name, args, out.name (), err.name ());
507
508      if ((status.type == rld::process::status::normal) &&
509          (status.code == 0))
510      {
511        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
512          out.output (cc_name, std::cout, true);
513        out.open ();
514        while (true)
515        {
516          std::string line;
517          out.read_line (line);
518          if (line.size () == 0)
519            break;
520          if (match_and_trim ("install: ", line, install_path))
521            continue;
522          if (match_and_trim ("programs: ", line, programs_path))
523            continue;
524          if (match_and_trim ("libraries: ", line, libraries_path))
525            continue;
526        }
527        out.close ();
528        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
529        {
530          std::cout << "cc::install: " << install_path << std::endl
531                    << "cc::programs: " << programs_path << std::endl
532                    << "cc::libraries: " << libraries_path << std::endl;
533        }
534      }
535      else
536      {
537        err.output (cc_name, std::cout);
538      }
539    }
540
541    void
542    get_library_path (std::string& name, std::string& path)
543    {
544      rld::process::arg_container args;
545
546      make_cc_command (args);
547      append_flags (ft_cppflags, args);
548      append_flags (ft_cflags, args);
549      args.push_back ("-print-file-name=" + name);
550
551      rld::process::tempfile out;
552      rld::process::tempfile err;
553      rld::process::status   status;
554
555      status = rld::process::execute (cc_name, args, out.name (), err.name ());
556
557      if ((status.type == rld::process::status::normal) &&
558          (status.code == 0))
559      {
560        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
561          out.output ("cc", std::cout, true);
562        out.open ();
563        out.read (path);
564        out.close ();
565        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
566          std::cout << "cc::libpath: " << name << " -> " << path << std::endl;
567      }
568      else
569      {
570        err.output ("cc", std::cout);
571      }
572    }
573
574    void
575    get_standard_libpaths (rld::path::paths& libpaths)
576    {
577      search_dirs ();
578      rld::path::paths stdlibpaths;
579      rld::split (stdlibpaths, libraries_path, RLD_PATHSTR_SEPARATOR);
580      libpaths.insert (libpaths.end (), stdlibpaths.begin (), stdlibpaths.end ());
581    }
582
583    void
584    get_standard_libs (rld::path::paths& libs,
585                       rld::path::paths& libpaths,
586                       bool              cplusplus)
587    {
588      strings libnames;
589
590      rld::split (libnames, std_lib_c, RLD_PATHSTR_SEPARATOR);
591      if (cplusplus)
592        rld::path::path_split (std_lib_cplusplus, libnames);
593
594      for (strings::iterator lni = libnames.begin ();
595           lni != libnames.end ();
596           ++lni)
597      {
598        if (rld::verbose () >= RLD_VERBOSE_INFO)
599          std::cout << "cc::stdlib: " << *lni << std::endl;
600
601        std::string path;
602
603        rld::path::find_file (path, *lni, libpaths);
604        if (path.empty ())
605          throw rld::error ("Library not found: " + *lni, "getting standard libs");
606
607        libs.push_back (path);
608      }
609    }
610  }
611}
Note: See TracBrowser for help on using the repository browser.