source: rtems-tools/rtemstoolkit/rld-cc.cpp @ 87e0e76

4.104.11
Last change on this file since 87e0e76 was 87e0e76, checked in by Chris Johns <chrisj@…>, on Sep 13, 2014 at 2:09:16 AM

Refactor code into the RTEMS Toolkit.

  • Property mode set to 100644
File size: 16.1 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 is_exec_prefix_set ()
289    {
290      return !exec_prefix.empty ();
291    }
292
293    void
294    set_flags (const std::string& flags,
295               const std::string& arch,
296               const std::string& path,
297               flag_type          type)
298    {
299      std::string* oflags;
300      switch (type)
301      {
302        case ft_cppflags:
303          oflags = &cppflags;
304          break;
305        case ft_cflags:
306          oflags = &cflags;
307          break;
308        case ft_cxxflags:
309          oflags = &cxxflags;
310          break;
311        case ft_ldflags:
312          oflags = &ldflags;
313          break;
314        default:
315          throw rld::error ("Invalid flag type", "CC set flags");
316      }
317      (*oflags) = filter_flags (flags, arch, path, type);
318    }
319
320    void
321    set_flags (const std::string& flags, flag_type type)
322    {
323      std::string arch;
324      std::string path;
325      set_flags (flags, arch, path, type);
326    }
327
328    void
329    append_flags (const std::string& flags,
330                  const std::string& arch,
331                  const std::string& path,
332                  flag_type          type)
333    {
334      std::string* oflags;
335      switch (type)
336      {
337        case ft_cppflags:
338          oflags = &cppflags;
339          break;
340        case ft_cflags:
341          oflags = &cflags;
342          break;
343        case ft_cxxflags:
344          oflags = &cxxflags;
345          break;
346        case ft_ldflags:
347          oflags = &ldflags;
348          break;
349        default:
350          throw rld::error ("Invalid flag type", "CC set flags");
351      }
352      if (oflags->empty ())
353        *oflags += filter_flags (flags, arch, path, type);
354      else
355        *oflags += ' ' + filter_flags (flags, arch, path, type);
356    }
357
358    void
359    append_flags (const std::string& flags, flag_type type)
360    {
361      std::string arch;
362      std::string path;
363      append_flags (flags, arch, path, type);
364    }
365
366    const std::string
367    get_flags (flag_type type)
368    {
369      std::string* flags;
370      switch (type)
371      {
372        case ft_cppflags:
373          flags = &cppflags;
374          break;
375        case ft_cflags:
376          flags = &cflags;
377          break;
378        case ft_cxxflags:
379          flags = &cxxflags;
380          break;
381        case ft_ldflags:
382          flags = &ldflags;
383          break;
384        default:
385          throw rld::error ("Invalid flag type", "CC get flags");
386      }
387      return *flags;
388    }
389
390    const std::string
391    get_flags (flag_group group)
392    {
393      std::string* flags;
394      switch (group)
395      {
396        case fg_warning_flags:
397          flags = &warning_cflags;
398          break;
399        case fg_include_flags:
400          flags = &include_cflags;
401          break;
402        case fg_machine_flags:
403          flags = &machine_cflags;
404          break;
405        case fg_spec_flags:
406          flags = &spec_cflags;
407          break;
408        default:
409          throw rld::error ("Invalid flag group", "CC get flags");
410      }
411      return *flags;
412    }
413
414    void
415    append_flags (flag_type type, rld::process::arg_container& args)
416    {
417      const std::string* flags = 0;
418      switch (type)
419      {
420        case ft_cppflags:
421          flags = &cppflags;
422          break;
423        case ft_cflags:
424          flags = &cflags;
425          break;
426        case ft_cxxflags:
427          flags = &cxxflags;
428          break;
429        case ft_ldflags:
430          flags = &ldflags;
431          break;
432        default:
433          throw rld::error ("Invalid flag type", "CC append flags");
434      }
435      if (!flags->empty ())
436        rld::process::args_append (args, *flags);
437    }
438
439    void
440    make_cc_command (rld::process::arg_container& args)
441    {
442      /*
443       * Use the absolute path to CC if provided.
444       */
445      if (is_cc_set ())
446      {
447        args.push_back (cc);
448      }
449      else
450      {
451        std::string cmd = cc_name;
452        if (!exec_prefix.empty ())
453          cmd = exec_prefix + "-rtems" + rld::rtems::version () + '-' + cmd;
454        args.push_back (cmd);
455      }
456    }
457
458    void
459    make_ld_command (rld::process::arg_container& args)
460    {
461      /*
462       * Use the absolute path to LD if provided.
463       */
464      if (is_ld_set ())
465      {
466        args.push_back (get_ld ());
467      }
468      else
469      {
470        std::string cmd = ld_name;
471        if (!exec_prefix.empty ())
472          cmd = exec_prefix + "-rtems" + rld::rtems::version () + '-' + cmd;
473        args.push_back (cmd);
474      }
475    }
476
477    static bool
478    match_and_trim (const char* prefix, std::string& line, std::string& result)
479    {
480      std::string::size_type pos = ::strlen (prefix);
481      if (line.substr (0, pos) == prefix)
482      {
483        if (line[pos] == '=')
484          ++pos;
485        result = line.substr (pos, line.size () - pos - 1);
486        return true;
487      }
488      return false;
489    }
490
491    static void
492    search_dirs ()
493    {
494      rld::process::arg_container args;
495
496      make_cc_command (args);
497      append_flags (ft_cppflags, args);
498      append_flags (ft_cflags, args);
499      args.push_back ("-print-search-dirs");
500
501      rld::process::tempfile out;
502      rld::process::tempfile err;
503      rld::process::status   status;
504
505      status = rld::process::execute (cc_name, args, out.name (), err.name ());
506
507      if ((status.type == rld::process::status::normal) &&
508          (status.code == 0))
509      {
510        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
511          out.output (cc_name, std::cout, true);
512        out.open ();
513        while (true)
514        {
515          std::string line;
516          out.read_line (line);
517          if (line.size () == 0)
518            break;
519          if (match_and_trim ("install: ", line, install_path))
520            continue;
521          if (match_and_trim ("programs: ", line, programs_path))
522            continue;
523          if (match_and_trim ("libraries: ", line, libraries_path))
524            continue;
525        }
526        out.close ();
527        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
528        {
529          std::cout << "cc::install: " << install_path << std::endl
530                    << "cc::programs: " << programs_path << std::endl
531                    << "cc::libraries: " << libraries_path << std::endl;
532        }
533      }
534      else
535      {
536        err.output (cc_name, std::cout);
537      }
538    }
539
540    void
541    get_library_path (std::string& name, std::string& path)
542    {
543      rld::process::arg_container args;
544
545      make_cc_command (args);
546      append_flags (ft_cppflags, args);
547      append_flags (ft_cflags, args);
548      args.push_back ("-print-file-name=" + name);
549
550      rld::process::tempfile out;
551      rld::process::tempfile err;
552      rld::process::status   status;
553
554      status = rld::process::execute (cc_name, args, out.name (), err.name ());
555
556      if ((status.type == rld::process::status::normal) &&
557          (status.code == 0))
558      {
559        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
560          out.output ("cc", std::cout, true);
561        out.open ();
562        out.read (path);
563        out.close ();
564        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
565          std::cout << "cc::libpath: " << name << " -> " << path << std::endl;
566      }
567      else
568      {
569        err.output ("cc", std::cout);
570      }
571    }
572
573    void
574    get_standard_libpaths (rld::path::paths& libpaths)
575    {
576      search_dirs ();
577      rld::split (libpaths, libraries_path, RLD_PATHSTR_SEPARATOR);
578    }
579
580    void
581    get_standard_libs (rld::path::paths& libs,
582                       rld::path::paths& libpaths,
583                       bool              cplusplus)
584    {
585      strings libnames;
586
587      rld::split (libnames, std_lib_c, RLD_PATHSTR_SEPARATOR);
588      if (cplusplus)
589        rld::path::path_split (std_lib_cplusplus, libnames);
590
591      for (strings::iterator lni = libnames.begin ();
592           lni != libnames.end ();
593           ++lni)
594      {
595        if (rld::verbose () >= RLD_VERBOSE_INFO)
596          std::cout << "cc::stdlib: " << *lni << std::endl;
597
598        std::string path;
599
600        rld::path::find_file (path, *lni, libpaths);
601        if (path.empty ())
602          throw rld::error ("Library not found: " + *lni, "getting standard libs");
603
604        libs.push_back (path);
605      }
606    }
607  }
608}
Note: See TracBrowser for help on using the repository browser.