From 38e6fa5293abb3a0f6634c0f29e99264229fb296 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 8 Sep 2017 10:15:09 +0000 Subject: [PATCH 1/3] Accept the --build-id option in goto-ld Includes clean-up of documentation placement and disable clang-format for the collection of options. --- src/goto-cc/ld_cmdline.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/goto-cc/ld_cmdline.cpp b/src/goto-cc/ld_cmdline.cpp index c77ee68773b..6e8efecb702 100644 --- a/src/goto-cc/ld_cmdline.cpp +++ b/src/goto-cc/ld_cmdline.cpp @@ -16,9 +16,7 @@ Author: Daniel Kroening, 2013 #include -/// parses the command line options into a cmdlinet -/// \par parameters: argument count, argument strings -/// \return none +// clang-format off const char *goto_ld_options_with_argument[]= { "--verbosity", @@ -99,6 +97,7 @@ const char *ld_options_with_argument[]= "--ios_version_min", // Apple only "--macosx_version_min", // Apple only "--install_name", // Apple only + "--build-id", nullptr }; @@ -235,7 +234,11 @@ const char *ld_options_without_argument[]= "--bundle", // Apple only nullptr }; +// clang-format on +/// parses the command line options into a cmdlinet +/// \par parameters: argument count, argument strings +/// \return none bool ld_cmdlinet::parse(int argc, const char **argv) { assert(argc>0); From e80008e780cf00a148d9b562c19cc6b6dadf2855 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sat, 10 Mar 2018 18:18:53 +0000 Subject: [PATCH 2/3] goto-cc: support GCC's print-sysroot* options Hand these over to an underlying native compiler, and do the same for all dump* options. Includes clean-up of documentation placement and disable clang-format for the collection of options. --- src/goto-cc/gcc_cmdline.cpp | 10 +++++++--- src/goto-cc/gcc_mode.cpp | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/goto-cc/gcc_cmdline.cpp b/src/goto-cc/gcc_cmdline.cpp index e4b2bb1ddb6..d2f5eefbe29 100644 --- a/src/goto-cc/gcc_cmdline.cpp +++ b/src/goto-cc/gcc_cmdline.cpp @@ -18,9 +18,7 @@ Author: CM Wintersteiger, 2006 #include -/// parses the command line options into a cmdlinet -/// \par parameters: argument count, argument strings -/// \return none +// clang-format off // non-gcc options const char *goto_cc_options_with_separated_argument[]= { @@ -163,6 +161,8 @@ const char *gcc_options_without_argument[]= "-print-multi-directory", "-print-multi-lib", "-print-search-dirs", + "-print-sysroot", + "-print-sysroot-headers-suffix", "-Q", "-Qn", "-Qy", @@ -211,7 +211,11 @@ const char *gcc_options_without_argument[]= "-fast", // Apple only nullptr }; +// clang-format on +/// parses the command line options into a cmdlinet +/// \par parameters: argument count, argument strings +/// \return none bool gcc_cmdlinet::parse(int argc, const char **argv) { assert(argc>0); diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 88c940aa9dc..fade9d0307b 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -380,12 +380,24 @@ int gcc_modet::doit() return EX_OK; // Exit! } - if(cmdline.isset("dumpversion")) + if( + cmdline.isset("dumpmachine") || cmdline.isset("dumpspecs") || + cmdline.isset("dumpversion") || cmdline.isset("print-sysroot") || + cmdline.isset("print-sysroot-headers-suffix")) { if(produce_hybrid_binary) return run_gcc(compiler); - std::cout << "3.4.4\n"; + // GCC will only print one of these, even when multiple arguments are + // passed, so we do the same + if(cmdline.isset("dumpmachine")) + std::cout << config.this_architecture() << '\n'; + else if(cmdline.isset("dumpversion")) + std::cout << "3.4.4\n"; + + // we don't have any meaningful output for the other options, and GCC + // doesn't necessarily produce non-empty output either + return EX_OK; } From 177c8c1f2b72c392a45c8e49edbd9e5f3a43d464 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 8 Mar 2018 20:53:32 +0000 Subject: [PATCH 3/3] goto-cc: support thin ar archives, refactoring The Linux kernel uses thin ar archives during the build process, which must be extracted the same way this was already done for .a files. To implement this, the file-type detection was factored out into a separate procedure. Additional behavioural change: files without extension are no longer ignored, but are instead tested for being goto binaries. --- src/goto-cc/compile.cpp | 250 +++++++++++++++++++++------------------- src/goto-cc/compile.h | 2 +- 2 files changed, 132 insertions(+), 120 deletions(-) diff --git a/src/goto-cc/compile.cpp b/src/goto-cc/compile.cpp index c2473ff9dc6..8b298260a99 100644 --- a/src/goto-cc/compile.cpp +++ b/src/goto-cc/compile.cpp @@ -13,6 +13,7 @@ Date: June 2006 #include "compile.h" +#include #include #include #include @@ -135,56 +136,114 @@ bool compilet::doit() warnings_before; } -/// puts input file names into a list and does preprocessing for libraries. -/// \return false on success, true on error. -bool compilet::add_input_file(const std::string &file_name) +enum class file_typet +{ + FAILED_TO_OPEN_FILE, + UNKNOWN, + SOURCE_FILE, + NORMAL_ARCHIVE, + THIN_ARCHIVE, + GOTO_BINARY, + ELF_OBJECT +}; + +static file_typet detect_file_type(const std::string &file_name) { // first of all, try to open the file - { - std::ifstream in(file_name); - if(!in) - { - warning() << "failed to open file `" << file_name << "'" << eom; - return warning_is_fatal; // generously ignore unless -Werror - } - } + std::ifstream in(file_name); + if(!in) + return file_typet::FAILED_TO_OPEN_FILE; + + const std::string::size_type r = file_name.rfind('.'); - size_t r=file_name.rfind('.', file_name.length()-1); + const std::string ext = + r == std::string::npos ? "" : file_name.substr(r + 1, file_name.length()); - if(r==std::string::npos) + if( + ext == "c" || ext == "cc" || ext == "cp" || ext == "cpp" || ext == "CPP" || + ext == "c++" || ext == "C" || ext == "i" || ext == "ii" || ext == "class" || + ext == "jar" || ext == "jsil") { - // a file without extension; will ignore - warning() << "input file `" << file_name - << "' has no extension, not considered" << eom; - return warning_is_fatal; + return file_typet::SOURCE_FILE; } - std::string ext = file_name.substr(r+1, file_name.length()); - - if(ext=="c" || - ext=="cc" || - ext=="cp" || - ext=="cpp" || - ext=="CPP" || - ext=="c++" || - ext=="C" || - ext=="i" || - ext=="ii" || - ext=="class" || - ext=="jar" || - ext=="jsil") + char hdr[8]; + in.get(hdr, 8); + if((ext == "a" || ext == "o") && strncmp(hdr, "!", 8) == 0) + return file_typet::THIN_ARCHIVE; + + if(ext == "a") + return file_typet::NORMAL_ARCHIVE; + + if(is_goto_binary(file_name)) + return file_typet::GOTO_BINARY; + + if(hdr[0] == 0x7f && memcmp(hdr + 1, "ELF", 3) == 0) + return file_typet::ELF_OBJECT; + + return file_typet::UNKNOWN; +} + +/// puts input file names into a list and does preprocessing for libraries. +/// \return false on success, true on error. +bool compilet::add_input_file(const std::string &file_name) +{ + switch(detect_file_type(file_name)) { + case file_typet::FAILED_TO_OPEN_FILE: + warning() << "failed to open file `" << file_name + << "': " << std::strerror(errno) << eom; + return warning_is_fatal; // generously ignore unless -Werror + + case file_typet::UNKNOWN: + // unknown extension, not a goto binary, will silently ignore + debug() << "unknown file type in `" << file_name << "'" << eom; + return false; + + case file_typet::ELF_OBJECT: + // ELF file without goto-cc section, silently ignore + debug() << "ELF object without goto-cc section: `" << file_name << "'" + << eom; + return false; + + case file_typet::SOURCE_FILE: source_files.push_back(file_name); + return false; + + case file_typet::NORMAL_ARCHIVE: + return add_files_from_archive(file_name, false); + + case file_typet::THIN_ARCHIVE: + return add_files_from_archive(file_name, true); + + case file_typet::GOTO_BINARY: + object_files.push_back(file_name); + return false; } - else if(ext=="a") - { - #ifdef _WIN32 - char td[MAX_PATH+1]; - #else - char td[] = "goto-cc.XXXXXX"; - #endif - std::string tstr=get_temporary_directory(td); + UNREACHABLE; +} + +/// extracts goto binaries from AR archive and add them as input files. +/// \return false on success, true on error. +bool compilet::add_files_from_archive( + const std::string &file_name, + bool thin_archive) +{ +#ifdef _WIN32 + char td[MAX_PATH + 1]; +#else + char td[] = "goto-cc.XXXXXX"; +#endif + + std::stringstream cmd; + FILE *stream; + + std::string tstr = working_directory; + + if(!thin_archive) + { + tstr = get_temporary_directory(td); if(tstr=="") { @@ -193,7 +252,6 @@ bool compilet::add_input_file(const std::string &file_name) } tmp_dirs.push_back(tstr); - std::stringstream cmd(""); if(chdir(tmp_dirs.back().c_str())!=0) { error() << "Cannot switch to temporary directory" << eom; @@ -203,76 +261,47 @@ bool compilet::add_input_file(const std::string &file_name) // unpack now cmd << "ar x " << concat_dir_file(working_directory, file_name); - FILE *stream; - stream=popen(cmd.str().c_str(), "r"); pclose(stream); cmd.clear(); cmd.str(""); + } - // add the files from "ar t" - #ifdef _WIN32 - if(file_name[0]!='/' && file_name[1]!=':') // NOLINT(readability/braces) - #else - if(file_name[0]!='/') // NOLINT(readability/braces) - #endif - { - cmd << "ar t " << - #ifdef _WIN32 - working_directory << "\\" << file_name; - #else - working_directory << "/" << file_name; - #endif - } - else - { - cmd << "ar t " << file_name; - } + // add the files from "ar t" + cmd << "ar t " << concat_dir_file(working_directory, file_name); - stream=popen(cmd.str().c_str(), "r"); + stream = popen(cmd.str().c_str(), "r"); - if(stream!=nullptr) + if(stream != nullptr) + { + std::string line; + int ch; // fgetc returns an int, not char + while((ch = fgetc(stream)) != EOF) { - std::string line; - int ch; // fgetc returns an int, not char - while((ch=fgetc(stream))!=EOF) + if(ch != '\n') { - if(ch!='\n') - { - line+=static_cast(ch); - } - else - { - std::string t; - #ifdef _WIN32 - t = tmp_dirs.back() + '\\' + line; - #else - t = tmp_dirs.back() + '/' + line; - #endif - - if(is_goto_binary(t)) - object_files.push_back(t); - - line = ""; - } + line += static_cast(ch); } + else + { + std::string t = concat_dir_file(tstr, line); - pclose(stream); - } + if(is_goto_binary(t)) + object_files.push_back(t); + else + debug() << "Object file is not a goto binary: " << line << eom; - cmd.str(""); + line = ""; + } + } - if(chdir(working_directory.c_str())!=0) - error() << "Could not change back to working directory" << eom; - } - else if(is_goto_binary(file_name)) - object_files.push_back(file_name); - else - { - // unknown extension, not a goto binary, will silently ignore + pclose(stream); } + if(!thin_archive && chdir(working_directory.c_str()) != 0) + error() << "Could not change back to working directory" << eom; + return false; } @@ -302,12 +331,17 @@ bool compilet::find_library(const std::string &name) { std::string libname=tmp+name+".so"; - if(is_goto_binary(libname)) - return !add_input_file(libname); - else if(is_elf_file(libname)) + switch(detect_file_type(libname)) { + case file_typet::GOTO_BINARY: + return !add_input_file(libname); + + case file_typet::ELF_OBJECT: warning() << "Warning: Cannot read ELF library " << libname << eom; return warning_is_fatal; + + default: + break; } } } @@ -315,28 +349,6 @@ bool compilet::find_library(const std::string &name) return false; } -/// checking if we can load an object file -/// \par parameters: file name -/// \return true if the given file name exists and is an ELF file, false -/// otherwise -bool compilet::is_elf_file(const std::string &file_name) -{ - std::fstream in; - - in.open(file_name, std::ios::in); - if(in.is_open()) - { - char buf[4]; - for(std::size_t i=0; i<4; i++) - buf[i]=static_cast(in.get()); - if(buf[0]==0x7f && buf[1]=='E' && - buf[2]=='L' && buf[3]=='F') - return true; - } - - return false; -} - /// parses object files and links them /// \return true on error, false otherwise bool compilet::link() diff --git a/src/goto-cc/compile.h b/src/goto-cc/compile.h index 4ae2a2eb0e0..839e340e792 100644 --- a/src/goto-cc/compile.h +++ b/src/goto-cc/compile.h @@ -53,7 +53,7 @@ class compilet:public language_uit bool add_input_file(const std::string &); bool find_library(const std::string &); - bool is_elf_file(const std::string &); + bool add_files_from_archive(const std::string &file_name, bool thin_archive); bool parse(const std::string &filename); bool parse_stdin();