// // aegis - project change supervisor // Copyright (C) 2012 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program. If not, see . // #include #include #include #include #include #include #include #include #include process_data::~process_data() { } process_data::process_data() : use_libtool_flag(false), use_lib_la_files_flag(false), use_x11_flag(false), use_i18n_flag(false), seen_c_flag(false), seen_c_plus_plus_flag(false), need_yacc_flag(false), have_yacc_flag(false), need_lex_flag(false), have_lex_flag(false), library_file_extension("a"), object_file_extension("o"), install_script_macro(false), etc_test_sh_flag(false), have_groff_flag(false), need_groff_flag(false), have_soelim_flag(false), need_soelim_flag(false), seen_datadir_flag(false), seen_datarootdir_flag(false), seen_libdir_flag(false), seen_sysconfdir_flag(false), have_nlsdir_flag(false), etc_msgfmt_sh_flag(false), groff_macro_flag(false), install_data_macro(false), have_ar_flag(false), have_ranlib_flag(false), need_ghostscript_flag(false), read_only(false) // must be last { } void process_data::notify_preprocess_complete(void) { read_only = true; } #if HAVE_BACKTRACE #include static void emit_backtrace(void) { enum { BT_MAX_DEPTH = 20 }; void **bt_info = new void * [BT_MAX_DEPTH]; if (bt_info) { int bt_depth = backtrace(bt_info, BT_MAX_DEPTH); char **symbol = backtrace_symbols(bt_info, bt_depth); for (int j = 0; j < bt_depth; ++j) { error_raw("%d: %s", j, symbol[j]); } delete [] bt_info; } } #endif void process_data::check_read_write(const char *method_name) { if (read_only) { #if HAVE_BACKTRACE emit_backtrace(); #endif // This will be fatal_raw shortly. error_raw ( "read-only mode in effect, may no longer call %s", method_name ); } } void process_data::set_use_libtool(void) { check_read_write(__PRETTY_FUNCTION__); use_libtool_flag = true; set_libext_libtool(); // This is so the install rule can use $(INSTALL_DATA) set_install_data_macro(); } void process_data::set_use_lib_la_files(void) { check_read_write(__PRETTY_FUNCTION__); use_lib_la_files_flag = true; } void process_data::set_use_x11(void) { check_read_write(__PRETTY_FUNCTION__); use_x11_flag = true; } void process_data::set_version_info(const nstring &text) { check_read_write(__PRETTY_FUNCTION__); nstring_list nl1; nl1.split(text, ":"); nstring_list nl2; while (nl2.size() < 3) { if (nl1.size() > nl2.size()) { long n = nl1[nl2.size()].to_long(); nl2.push_back(nstring::format("%ld", n)); } else nl2.push_back("0"); } version_info = nl2.unsplit(":"); } nstring process_data::get_version_info(void) const { return version_info; } nstring process_data::get_version_info_major(void) const { // // This is weirder than you think. It actually wants $1-$3 // (revision - age) not just $1 (revision), because this is the name // that libtool actually links to. Sigh. // nstring_list parts; parts.split(version_info, ":"); switch (parts.size()) { case 0: // Should never happen, but cope. return "0"; case 1: case 2: // Should never happen, but cope. return parts[0]; case 3: // This is the normal case. break; default: assert(!"this should not happen, because we already sanitized it"); break; } return nstring::format("%ld", parts[0].to_long() - parts[2].to_long()); } void process_data::set_library_directory(change_identifier &cid, const nstring_list &filenames) { check_read_write(__PRETTY_FUNCTION__); project_name = nstring(cid.get_pp()->trunk_get()->name_get()); // // scan the list of file names, looking for a "lib*" directory with // C++ or C files in it. Use the first one as the library directory. // library_directory = cid.get_cp()->pconf_attributes_find("aemakegen:library-directory"); if (!library_directory.empty()) { library_name = library_directory; if (library_directory == "lib") library_name = project_name; if (!library_name.starts_with("lib")) library_name = "lib" + library_name; } else { nstring_list libdirs; for (size_t j = 0; j < filenames.size(); ++j) { nstring filename = filenames[j]; if (filename.starts_with("lib") && is_a_source_file(filename)) { nstring dir = filename.first_dirname(); // libdir is supposed to contain files to be installed // into $(libdir), not sources. if (dir != "." && dir != "libdir") libdirs.push_back_unique(dir); } } libdirs.sort(); if (!libdirs.empty()) { library_directory = libdirs[0]; library_name = library_directory; if (library_directory == "lib") library_name = project_name; if (!library_name.starts_with("lib")) library_name = "lib" + library_name; } } } void process_data::remember_explicit_noinst(const nstring &progname) { check_read_write(__PRETTY_FUNCTION__); explicit_noinst.push_back_unique(progname); } bool process_data::is_explicit_noinst(const nstring &progname) const { return explicit_noinst.member(progname); } bool process_data::uses_pkgconfig(void) const { return (use_libtool_flag && seen_pkgconfig_source()); } void process_data::remember_clean_misc_file(const nstring &filename) { clean_misc_files.push_back_unique(filename); } void process_data::remember_clean_obj_file(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); clean_obj_files.push_back_unique(filename); } void process_data::remember_dist_clean_file(const nstring &filename) { dist_clean_files.push_back_unique(filename); } void process_data::remember_dist_clean_dir(const nstring &path) { dist_clean_dirs.push_back_unique(path); } void process_data::set_exeext(void) { check_read_write(__PRETTY_FUNCTION__); executable_file_extension = "$(EXEEXT)"; } nstring process_data::libext(void) const { if (use_libtool_flag) return "la"; return library_file_extension; } void process_data::set_libext(void) { check_read_write(__PRETTY_FUNCTION__); library_file_extension = "$(LIBEXT)"; } void process_data::set_libext_libtool(void) { check_read_write(__PRETTY_FUNCTION__); library_file_extension = "la"; } void process_data::set_objext(void) { check_read_write(__PRETTY_FUNCTION__); object_file_extension = "$(OBJEXT)"; } void process_data::remember_source_file(const nstring &path) { trace(("%s {\n", __PRETTY_FUNCTION__)); trace(("path = %s\n", path.quote_c().c_str())); check_read_write(__PRETTY_FUNCTION__); nstring srcdir = progname_from_dir_of(path); trace(("srcdir = %s\n", srcdir.quote_c().c_str())); source_list_t::iterator it = source_list.find(srcdir); if (it == source_list.end()) { nstring_list tmp; tmp.push_back(path); source_list.insert(source_list_t::value_type(srcdir, tmp)); } else { it->second.push_back(path); } trace(("}\n")); } const nstring_list & process_data::get_source_files_by_dir(const nstring &dir) const { source_list_t::const_iterator it = source_list.find(dir); if (it == source_list.end()) { static nstring_list fail; return fail; } return it->second; } void process_data::remember_include_files_by_dir(const nstring &path) { trace(("%s {\n", __PRETTY_FUNCTION__)); trace(("path = %s\n", path.quote_c().c_str())); check_read_write(__PRETTY_FUNCTION__); assert(is_an_include_file(path)); nstring objdir = progname_from_dir_of(path); trace(("objdir = %s\n", objdir.quote_c().c_str())); include_list_t::iterator it = include_list.find(objdir); if (it == include_list.end()) { nstring_list tmp; tmp.push_back(path); include_list.insert(include_list_t::value_type(objdir, tmp)); } else { it->second.push_back(path); } trace(("}\n")); } const nstring_list & process_data::get_include_files_by_dir(const nstring &dir) const { include_list_t::const_iterator it = include_list.find(dir); if (it == include_list.end()) { static nstring_list fail; return fail; } return it->second; } void process_data::remember_object_file(const nstring &path) { trace(("%s {\n", __PRETTY_FUNCTION__)); trace(("path = %s\n", path.quote_c().c_str())); check_read_write(__PRETTY_FUNCTION__); assert(path.ends_with("." + objext()) || path.ends_with(".o") || path.ends_with(".lo")); // // See if the path is below any of the progdirs. // Otherwise, just use the first dir. // nstring objdir = path.first_dirname(); for (size_t j = 0; j < progdirs.size(); ++j) { nstring dir = progdirs[j]; nstring relative = os_below_dir(dir, path); trace(("relative = %s\n", relative.quote_c().c_str())); if (!relative.empty()) { assert(relative != "."); objdir = dir; break; } } trace(("objdir = %s\n", objdir.quote_c().c_str())); object_list_t::iterator it = object_list.find(objdir); if (it == object_list.end()) { nstring_list tmp; tmp.push_back(path); object_list.insert(object_list_t::value_type(objdir, tmp)); } else { it->second.push_back(path); } remember_clean_obj_file(path); trace(("}\n")); } const nstring_list & process_data::get_object_files_by_dir(const nstring &dir) const { object_list_t::const_iterator it = object_list.find(dir); if (it == object_list.end()) { static nstring_list fail; return fail; } return it->second; } void process_data::library_plus_library(const nstring &to_name, const nstring &from_name) { check_read_write(__PRETTY_FUNCTION__); object_list_t::iterator to_obj_list = object_list.find(to_name); if (to_obj_list == object_list.end()) return; object_list_t::const_iterator from_obj_list = object_list.find(from_name); if (from_obj_list == object_list.end()) return; to_obj_list->second.push_back(from_obj_list->second); } void process_data::program_needs_library(const nstring &prog_name, const nstring &lib_name) { check_read_write(__PRETTY_FUNCTION__); library_list_t::iterator lnames = library_list.find(prog_name); if (lnames == library_list.end()) { nstring_list tmp; library_list.insert(library_list_t::value_type(prog_name, tmp)); lnames = library_list.find(prog_name); assert(lnames != library_list.end()); } // If you want to say "this program has no library dependencies" // pass the empty string for the library name. if (lib_name.empty()) return; nstring library_dirname = lib_name; nstring library_libname = library_dirname; if (library_libname == "lib") library_libname = project_name; if (!library_libname.starts_with("lib")) library_libname = "lib" + library_libname; nstring path = library_dirname + "/" + library_libname + "." + libext(); lnames->second.push_back(path); } const nstring_list & process_data::get_library_list_by_program(const nstring &prog_name) const { library_list_t::const_iterator it = library_list.find(prog_name); if (it == library_list.end()) { static nstring_list fail; return fail; } return it->second; } void process_data::remember_progdir(const nstring &progdir) { trace(("%s\n", __PRETTY_FUNCTION__)); trace(("progdir = %s\n", progdir.quote_c().c_str())); check_read_write(__PRETTY_FUNCTION__); progdirs.push_back_unique(progdir); } void process_data::remember_all_bin(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); all_bin.push_back_unique(filename); } void process_data::remember_install_directory_for(const nstring &filename) { assert(filename[0] == '$'); nstring dir = filename.dirname(); for (;;) { // When we get to the top of the directory tree, we are done. if (dir == "." || dir == "/") break; // if the directory is already known, nothing more needs to be done. if (install_directories.find(dir) != install_directories.end()) break; // Add the directory to the set of known directories. install_directories.insert(install_directories_t::value_type(dir, 1)); remember_clean_misc_file(make_pseudo_dir(dir)); // Move one level up the directory tree. dir = dir.dirname(); } } nstring_list process_data::get_install_directories(void) const { nstring_list result; for ( install_directories_t::const_iterator it = install_directories.begin(); it != install_directories.end(); ++it ) { result.push_back(it->first); } return result; } void process_data::remember_install_bin(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); install_bin.push_back_unique(filename); remember_install_directory_for(filename); } void process_data::remember_test_source(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); test_sources.push_back_unique(filename); } void process_data::remember_test_file(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); test_files.push_back_unique(filename); } void process_data::remember_install_datadir(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); install_datadir.push_back_unique(filename); remember_install_directory_for(filename); set_install_data_macro(); } void process_data::remember_pkgconfig_source(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); pkgconfig_sources.push_back_unique(filename); } void process_data::remember_install_libdir(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); install_libdir.push_back_unique(filename); remember_install_directory_for(filename); set_install_data_macro(); set_seen_libdir(); } void process_data::remember_man_sources(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); man_sources.push_back_unique(filename); } void process_data::remember_install_mandir(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); install_mandir.push_back_unique(filename); remember_install_directory_for(filename); set_install_data_macro(); } void process_data::remember_all_doc(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); all_doc.push_back_unique(filename); } void process_data::remember_install_doc(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); install_doc.push_back_unique(filename); remember_install_directory_for(filename); set_install_data_macro(); } void process_data::set_program_prefix(void) { program_prefix = "$(PROGRAM_PREFIX)"; } void process_data::set_program_suffix(void) { program_suffix = "$(PROGRAM_SUFFIX)"; } void process_data::remember_all_i18n(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); all_i18n.push_back_unique(filename); } void process_data::remember_install_i18n(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); install_i18n.push_back_unique(filename); remember_install_directory_for(filename); set_install_data_macro(); } void process_data::set_etc_msgfmt_sh(void) { check_read_write(__PRETTY_FUNCTION__); etc_msgfmt_sh_flag = true; } void process_data::remember_install_include_source(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); assert(filename[0] != '$'); assert(filename[0] != '/'); install_include_sources.push_back_unique(filename); } void process_data::remember_install_include(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); assert(filename[0] == '$'); install_include.push_back_unique(filename); remember_install_directory_for(filename); set_install_data_macro(); } void process_data::set_groff_macro(void) { check_read_write(__PRETTY_FUNCTION__); groff_macro_flag = true; } bool process_data::seen_programs(void) const { return !progdirs.empty(); } nstring process_data::progdir_from_progname(const nstring &progname) const { for (size_t j = 0; j < progdirs.size(); ++j) { nstring dir = progdirs[j]; nstring pn2 = progname_from_dir_of(dir + "/main.c"); if (progname == pn2) return dir; } return nstring(); } nstring_list process_data::get_programs(void) const { nstring_list result; for (size_t j = 0; j < progdirs.size(); ++j) { nstring dir = progdirs[j]; nstring progname = progname_from_dir_of(dir + "/main.c"); result.push_back(progname); } result.sort(); return result; } nstring_list process_data::get_list_of_library_directories(void) const { // Use a map for efficiency. Some of my projects have both many // directories and many programs, and the O(n**2) shows up very // quickly, so change to O(n*log(n)) typedef std::map progs_t; progs_t progs; for (size_t j = 0; j < progdirs.size(); ++j) { progs[progdirs[j]] = 1; } // // Build a list of directories that contain object files that // are not listed in the 'programs' list. They may not all be // libraries, but its a reasonably good guess. // nstring_list result; for ( object_list_t::const_iterator it = object_list.begin(); it != object_list.end(); ++it ) { if (progs.find(it->first) == progs.end()) { result.push_back(it->first); } } return result; } void process_data::remember_extra_dist(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); extra_dist.push_back_unique(filename); } void process_data::remember_built_sources(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); built_sources.push_back_unique(filename); } void process_data::set_install_data_macro(void) { check_read_write(__PRETTY_FUNCTION__); install_data_macro = true; } void process_data::set_have_ar(void) { check_read_write(__PRETTY_FUNCTION__); have_ar_flag = true; } void process_data::set_have_groff(void) { check_read_write(__PRETTY_FUNCTION__); have_groff_flag = true; } void process_data::set_need_groff(void) { check_read_write(__PRETTY_FUNCTION__); need_groff_flag = true; if (!have_groff_flag) { fatal_raw ( "The \"configure.ac\" file fails to invoke " "\"AC_CHECK_PROGS(GROFF, groff roff)\" and yet the project source " "files would appear to require it." ); } } void process_data::set_have_soelim(void) { check_read_write(__PRETTY_FUNCTION__); have_soelim_flag = true; } void process_data::set_need_soelim(void) { check_read_write(__PRETTY_FUNCTION__); need_soelim_flag = true; if (!have_soelim_flag) { fatal_raw ( "The \"configure.ac\" file fails to invoke " "\"AC_CHECK_PROGS(SOELIM, gsoelim soelim)\" and yet the project " "source files would appear to require it." ); } } void process_data::set_have_ranlib(void) { check_read_write(__PRETTY_FUNCTION__); have_ranlib_flag = true; } void process_data::set_need_ghostscript(void) { check_read_write(__PRETTY_FUNCTION__); need_ghostscript_flag = true; } void process_data::remember_am_data_data(const nstring &filename) { check_read_write(__PRETTY_FUNCTION__); am_data_data.push_back_unique(filename); } void process_data::set_have_nlsdir(void) { check_read_write(__PRETTY_FUNCTION__); have_nlsdir_flag = true; } // vim: set ts=8 sw=4 et :