source: rtems-tools/rtemstoolkit/rld-cc.cpp @ 53dd5e6

5
Last change on this file since 53dd5e6 was 36fde51, checked in by Joel Sherrill <joel@…>, on 10/14/18 at 21:58:20

rtemstoolkit/rld-cc.cpp: Accept -EL, -EB, and -Gn machine flags

closes #3401, #3402, $3424.

  • Property mode set to 100644
File size: 16.3 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_machine, "-G",       1, false, 0 },
117          { fg_machine, "-E",       1, false, 0 },
118          { fg_specs,   "-q",       1, false, 0 },
119          { fg_specs,   "-B",       2, true,  0 },
120          { fg_specs,   "--specs",  2, false, 0 }
121        };
122      const int flag_def_size = sizeof (flag_defs) / sizeof (flag_def);
123
124      std::string  oflags;
125      rld::strings flags_;
126
127      rld::split (flags_, strip_cflags (flags));
128
129      warnings.clear ();
130      includes.clear ();
131      machines.clear ();
132      specs.clear ();
133
134      for (rld::strings::iterator si = flags_.begin ();
135           si != flags_.end ();
136           ++si)
137      {
138        std::string  opts;
139        std::string& opt = *(si);
140        bool         in = true;
141
142        for (int fd = 0; fd < flag_def_size; ++fd)
143        {
144          if (rld::starts_with (opt, flag_defs[fd].opt))
145          {
146            int opt_count = flag_defs[fd].count;
147            if (opt_count > 1)
148            {
149              /*
150               * See if the flag is just the option. If is not take one less
151               * because the option's argument is joined to the option.
152               */
153              if (opt != flag_defs[fd].opt)
154              {
155                opt_count -= 1;
156                /*
157                 * @todo Path processing here. Not sure what it is needed for.
158                 */
159              }
160            }
161            opts += ' ' + opt;
162            while (opt_count > 1)
163            {
164              ++si;
165              /*
166               * @todo Path processing here. Not sure what it is needed for.
167               */
168              opts += ' ' + (*si);
169              --opt_count;
170            }
171            switch (flag_defs[fd].group)
172            {
173              case fg_warning:
174                warnings += ' ' + opts;
175                break;
176              case fg_include:
177                includes += ' ' + opts;
178                break;
179              case fg_machine:
180                machines += ' ' + opts;
181                break;
182              case fg_specs:
183                specs += ' ' + opts;
184                break;
185              default:
186                throw rld::error ("Invalid group", "flag group");
187            }
188            if ((flag_defs[fd].out & type) != 0)
189              in = false;
190            break;
191          }
192        }
193
194        if (in)
195          oflags += ' ' + opts;
196      }
197
198      rld::trim (warnings);
199      rld::trim (includes);
200      rld::trim (machines);
201      rld::trim (specs);
202
203      return rld::trim (oflags);
204    }
205
206    const std::string
207    filter_flags (const std::string& flags,
208                  const std::string& arch,
209                  const std::string& path,
210                  flag_type          type)
211    {
212      if (type != ft_cflags)
213      {
214        std::string warnings;
215        std::string includes;
216        std::string machines;
217        std::string specs;
218        return filter_flags (flags,
219                             arch,
220                             path,
221                             type,
222                             warnings,
223                             includes,
224                             machines,
225                             specs);
226      }
227      else
228      {
229        return filter_flags (flags,
230                             arch,
231                             path,
232                             type,
233                             warning_cflags,
234                             include_cflags,
235                             machine_cflags,
236                             spec_cflags);
237      }
238    }
239
240    void
241    set_cc (const std::string& cc_)
242    {
243      cc = cc_;
244      cc_set = true;
245    }
246
247    const std::string
248    get_cc ()
249    {
250      return cc;
251    }
252
253    bool
254    is_cc_set ()
255    {
256      return cc_set;
257    }
258
259    void
260    set_ld (const std::string& ld_)
261    {
262      ld = ld_;
263      ld_set = true;
264    }
265
266    const std::string
267    get_ld ()
268    {
269      return ld;
270    }
271
272    bool
273    is_ld_set ()
274    {
275      return ld_set;
276    }
277
278    void
279    set_exec_prefix (const std::string& exec_prefix_)
280    {
281      exec_prefix = exec_prefix_;
282    }
283
284    const std::string
285    get_exec_prefix ()
286    {
287      return exec_prefix;
288    }
289
290    bool
291    is_exec_prefix_set ()
292    {
293      return !exec_prefix.empty ();
294    }
295
296    void
297    set_flags (const std::string& flags,
298               const std::string& arch,
299               const std::string& path,
300               flag_type          type)
301    {
302      std::string* oflags;
303      switch (type)
304      {
305        case ft_cppflags:
306          oflags = &cppflags;
307          break;
308        case ft_cflags:
309          oflags = &cflags;
310          break;
311        case ft_cxxflags:
312          oflags = &cxxflags;
313          break;
314        case ft_ldflags:
315          oflags = &ldflags;
316          break;
317        default:
318          throw rld::error ("Invalid flag type", "CC set flags");
319      }
320      (*oflags) = filter_flags (flags, arch, path, type);
321    }
322
323    void
324    set_flags (const std::string& flags, flag_type type)
325    {
326      std::string arch;
327      std::string path;
328      set_flags (flags, arch, path, type);
329    }
330
331    void
332    append_flags (const std::string& flags,
333                  const std::string& arch,
334                  const std::string& path,
335                  flag_type          type)
336    {
337      std::string* oflags;
338      switch (type)
339      {
340        case ft_cppflags:
341          oflags = &cppflags;
342          break;
343        case ft_cflags:
344          oflags = &cflags;
345          break;
346        case ft_cxxflags:
347          oflags = &cxxflags;
348          break;
349        case ft_ldflags:
350          oflags = &ldflags;
351          break;
352        default:
353          throw rld::error ("Invalid flag type", "CC set flags");
354      }
355      if (oflags->empty ())
356        *oflags += filter_flags (flags, arch, path, type);
357      else
358        *oflags += ' ' + filter_flags (flags, arch, path, type);
359    }
360
361    void
362    append_flags (const std::string& flags, flag_type type)
363    {
364      std::string arch;
365      std::string path;
366      append_flags (flags, arch, path, type);
367    }
368
369    const std::string
370    get_flags (flag_type type)
371    {
372      std::string* flags;
373      switch (type)
374      {
375        case ft_cppflags:
376          flags = &cppflags;
377          break;
378        case ft_cflags:
379          flags = &cflags;
380          break;
381        case ft_cxxflags:
382          flags = &cxxflags;
383          break;
384        case ft_ldflags:
385          flags = &ldflags;
386          break;
387        default:
388          throw rld::error ("Invalid flag type", "CC get flags");
389      }
390      return *flags;
391    }
392
393    const std::string
394    get_flags (flag_group group)
395    {
396      std::string* flags;
397      switch (group)
398      {
399        case fg_warning_flags:
400          flags = &warning_cflags;
401          break;
402        case fg_include_flags:
403          flags = &include_cflags;
404          break;
405        case fg_machine_flags:
406          flags = &machine_cflags;
407          break;
408        case fg_spec_flags:
409          flags = &spec_cflags;
410          break;
411        default:
412          throw rld::error ("Invalid flag group", "CC get flags");
413      }
414      return *flags;
415    }
416
417    void
418    append_flags (flag_type type, rld::process::arg_container& args)
419    {
420      const std::string* flags = 0;
421      switch (type)
422      {
423        case ft_cppflags:
424          flags = &cppflags;
425          break;
426        case ft_cflags:
427          flags = &cflags;
428          break;
429        case ft_cxxflags:
430          flags = &cxxflags;
431          break;
432        case ft_ldflags:
433          flags = &ldflags;
434          break;
435        default:
436          throw rld::error ("Invalid flag type", "CC append flags");
437      }
438      if (!flags->empty ())
439        rld::process::args_append (args, *flags);
440    }
441
442    void
443    make_cc_command (rld::process::arg_container& args)
444    {
445      /*
446       * Use the absolute path to CC if provided.
447       */
448      if (is_cc_set ())
449      {
450        args.push_back (cc);
451      }
452      else
453      {
454        std::string cmd = cc_name;
455        if (!exec_prefix.empty ())
456          cmd = exec_prefix + "-rtems" + rld::rtems::version () + '-' + cmd;
457        args.push_back (cmd);
458      }
459    }
460
461    void
462    make_ld_command (rld::process::arg_container& args)
463    {
464      /*
465       * Use the absolute path to LD if provided.
466       */
467      if (is_ld_set ())
468      {
469        args.push_back (get_ld ());
470      }
471      else
472      {
473        std::string cmd = ld_name;
474        if (!exec_prefix.empty ())
475          cmd = exec_prefix + "-rtems" + rld::rtems::version () + '-' + cmd;
476        args.push_back (cmd);
477      }
478    }
479
480    static bool
481    match_and_trim (const char* prefix, std::string& line, std::string& result)
482    {
483      std::string::size_type pos = ::strlen (prefix);
484      if (line.substr (0, pos) == prefix)
485      {
486        if (line[pos] == '=')
487          ++pos;
488        result = line.substr (pos, line.size () - pos - 1);
489        return true;
490      }
491      return false;
492    }
493
494    static void
495    search_dirs ()
496    {
497      rld::process::arg_container args;
498
499      make_cc_command (args);
500      append_flags (ft_cppflags, args);
501      append_flags (ft_cflags, args);
502      args.push_back ("-print-search-dirs");
503
504      rld::process::tempfile out;
505      rld::process::tempfile err;
506      rld::process::status   status;
507
508      status = rld::process::execute (cc_name, args, out.name (), err.name ());
509
510      if ((status.type == rld::process::status::normal) &&
511          (status.code == 0))
512      {
513        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
514          out.output (cc_name, std::cout, true);
515        out.open ();
516        while (true)
517        {
518          std::string line;
519          out.read_line (line);
520          if (line.size () == 0)
521            break;
522          if (match_and_trim ("install: ", line, install_path))
523            continue;
524          if (match_and_trim ("programs: ", line, programs_path))
525            continue;
526          if (match_and_trim ("libraries: ", line, libraries_path))
527            continue;
528        }
529        out.close ();
530        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
531        {
532          std::cout << "cc::install: " << install_path << std::endl
533                    << "cc::programs: " << programs_path << std::endl
534                    << "cc::libraries: " << libraries_path << std::endl;
535        }
536      }
537      else
538      {
539        err.output (cc_name, std::cout);
540      }
541    }
542
543    void
544    get_library_path (std::string& name, std::string& path)
545    {
546      rld::process::arg_container args;
547
548      make_cc_command (args);
549      append_flags (ft_cppflags, args);
550      append_flags (ft_cflags, args);
551      args.push_back ("-print-file-name=" + name);
552
553      rld::process::tempfile out;
554      rld::process::tempfile err;
555      rld::process::status   status;
556
557      status = rld::process::execute (cc_name, args, out.name (), err.name ());
558
559      if ((status.type == rld::process::status::normal) &&
560          (status.code == 0))
561      {
562        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
563          out.output ("cc", std::cout, true);
564        out.open ();
565        out.read (path);
566        out.close ();
567        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
568          std::cout << "cc::libpath: " << name << " -> " << path << std::endl;
569      }
570      else
571      {
572        err.output ("cc", std::cout);
573      }
574    }
575
576    void
577    get_standard_libpaths (rld::path::paths& libpaths)
578    {
579      search_dirs ();
580      rld::path::paths stdlibpaths;
581      rld::split (stdlibpaths, libraries_path, RLD_PATHSTR_SEPARATOR);
582      libpaths.insert (libpaths.end (), stdlibpaths.begin (), stdlibpaths.end ());
583    }
584
585    void
586    get_standard_libs (rld::path::paths& libs,
587                       rld::path::paths& libpaths,
588                       bool              cplusplus)
589    {
590      strings libnames;
591
592      rld::split (libnames, std_lib_c, RLD_PATHSTR_SEPARATOR);
593      if (cplusplus)
594        rld::path::path_split (std_lib_cplusplus, libnames);
595
596      for (strings::iterator lni = libnames.begin ();
597           lni != libnames.end ();
598           ++lni)
599      {
600        if (rld::verbose () >= RLD_VERBOSE_INFO)
601          std::cout << "cc::stdlib: " << *lni << std::endl;
602
603        std::string path;
604
605        rld::path::find_file (path, *lni, libpaths);
606        if (path.empty ())
607          throw rld::error ("Library not found: " + *lni, "getting standard libs");
608
609        libs.push_back (path);
610      }
611    }
612  }
613}
Note: See TracBrowser for help on using the repository browser.