// file : odb/plugin.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file #include // Keep it first. #include // std::auto_ptr #include #include #include // std::strcpy #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace semantics; using cutl::fs::path; using cutl::fs::invalid_path; typedef vector paths; int plugin_is_GPL_compatible; auto_ptr options_; paths profile_paths_; path file_; // File being compiled. // A prefix of the _cpp_file struct. This struct is not part of the // public interface so we have to resort to this technique (based on // libcpp/files.c). // struct cpp_file_prefix { char const* name; char const* path; char const* pchname; char const* dir_name; }; extern "C" void start_unit_callback (void*, void*) { // Set the directory of the main file (stdin) to that of the orginal // file. // cpp_buffer* b (cpp_get_buffer (parse_in)); _cpp_file* f (cpp_get_file (b)); char const* p (cpp_get_path (f)); cpp_file_prefix* fp (reinterpret_cast (f)); // Perform sanity checks. // if (p != 0 && *p == '\0' // The path should be empty (stdin). && cpp_get_prev (b) == 0 // This is the only buffer (main file). && fp->path == p // Our prefix corresponds to the actual type. && fp->dir_name == 0) // The directory part hasn't been initialized. { path d (file_.directory ()); char* s; if (d.empty ()) { s = XNEWVEC (char, 1); *s = '\0'; } else { size_t n (d.string ().size ()); s = XNEWVEC (char, n + 2); strcpy (s, d.string ().c_str ()); s[n] = path::traits::directory_separator; s[n + 1] = '\0'; } fp->dir_name = s; } else { cerr << "ice: unable to initialize main file directory" << endl; exit (1); } } extern "C" void gate_callback (void*, void*) { // If there were errors during compilation, let GCC handle the // exit. // if (errorcount || sorrycount) return; int r (0); try { parser p (*options_, loc_pragmas_, decl_pragmas_); auto_ptr u (p.parse (global_namespace, file_)); // Validate, pass 1. // validator v; v.validate (*options_, *u, file_, 1); // Process. // processor pr; pr.process (*options_, *u, file_); // Validate, pass 2. // v.validate (*options_, *u, file_, 2); // Generate. // generator g; g.generate (*options_, *u, file_); } catch (parser::failed const&) { // Diagnostics has aready been issued. // r = 1; } catch (validator::failed const&) { // Diagnostics has aready been issued. // r = 1; } catch (processor::failed const&) { // Diagnostics has aready been issued. // r = 1; } catch (generator::failed const&) { // Diagnostics has aready been issued. // r = 1; } exit (r); } static char const* const odb_version = ODB_COMPILER_VERSION_STR; typedef vector strings; extern "C" int plugin_init (plugin_name_args* plugin_info, plugin_gcc_version*) { int r (0); plugin_info->version = odb_version; try { // Parse options. // { strings argv_str; vector argv; argv_str.push_back (plugin_info->base_name); argv.push_back (const_cast (argv_str.back ().c_str ())); for (int i (0); i < plugin_info->argc; ++i) { plugin_argument& a (plugin_info->argv[i]); // Handle service options. // if (strcmp (a.key, "svc-path") == 0) { profile_paths_.push_back (path (a.value)); continue; } if (strcmp (a.key, "svc-file") == 0) { file_ = path (a.value); continue; } string opt (strlen (a.key) > 1 ? "--" : "-"); opt += a.key; argv_str.push_back (opt); argv.push_back (const_cast (argv_str.back ().c_str ())); if (a.value != 0) { argv_str.push_back (a.value); argv.push_back (const_cast (argv_str.back ().c_str ())); } } // Two-phase options parsing, similar to the driver. // int argc (static_cast (argv.size ())); cli::argv_file_scanner::option_info oi[3]; oi[0].option = "--options-file"; oi[0].search_func = 0; oi[1].option = "-p"; oi[2].option = "--profile"; database db; { oi[1].search_func = &profile_search_ignore; oi[2].search_func = &profile_search_ignore; cli::argv_file_scanner scan (argc, &argv[0], oi, 3); options ops (scan); assert (ops.database_specified ()); db = ops.database (); } profile_data pd (profile_paths_, db, "odb plugin"); oi[1].search_func = &profile_search; oi[2].search_func = &profile_search; oi[1].arg = &pd; oi[2].arg = &pd; cli::argv_file_scanner scan (argc, &argv[0], oi, 3); auto_ptr ops ( new options (scan, cli::unknown_mode::fail, cli::unknown_mode::fail)); // Process options. // process_options (*ops); options_ = ops; } if (options_->trace ()) cerr << "starting plugin " << plugin_info->base_name << endl; // Disable assembly output. // asm_file_name = HOST_BIT_BUCKET; // Register callbacks. // register_callback (plugin_info->base_name, PLUGIN_PRAGMAS, register_odb_pragmas, 0); register_callback (plugin_info->base_name, PLUGIN_START_UNIT, start_unit_callback, 0); register_callback (plugin_info->base_name, PLUGIN_OVERRIDE_GATE, &gate_callback, 0); } catch (cli::exception const& ex) { cerr << ex << endl; r = 1; } if (r != 0) exit (r); return r; }