From 64fedd051ba4324436b67850353375a52dcfdec0 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 25 Jul 2018 17:14:17 +0100 Subject: [PATCH] Microsoft LINK personality --- src/goto-cc/Makefile | 2 + src/goto-cc/goto_cc_main.cpp | 24 ++- src/goto-cc/ms_link_cmdline.cpp | 368 ++++++++++++++++++++++++++++++++ src/goto-cc/ms_link_cmdline.h | 36 ++++ src/goto-cc/ms_link_mode.cpp | 84 ++++++++ src/goto-cc/ms_link_mode.h | 34 +++ 6 files changed, 540 insertions(+), 8 deletions(-) create mode 100644 src/goto-cc/ms_link_cmdline.cpp create mode 100644 src/goto-cc/ms_link_cmdline.h create mode 100644 src/goto-cc/ms_link_mode.cpp create mode 100644 src/goto-cc/ms_link_mode.h diff --git a/src/goto-cc/Makefile b/src/goto-cc/Makefile index 3e8e6e8bdb..cd65510265 100644 --- a/src/goto-cc/Makefile +++ b/src/goto-cc/Makefile @@ -19,6 +19,8 @@ SRC = armcc_cmdline.cpp \ linker_script_merge.cpp \ ms_cl_cmdline.cpp \ ms_cl_mode.cpp \ + ms_link_cmdline.cpp \ + ms_link_mode.cpp \ # Empty last line OBJ += ../big-int/big-int$(LIBEXT) \ diff --git a/src/goto-cc/goto_cc_main.cpp b/src/goto-cc/goto_cc_main.cpp index ab601a2c00..077ee8021d 100644 --- a/src/goto-cc/goto_cc_main.cpp +++ b/src/goto-cc/goto_cc_main.cpp @@ -17,13 +17,14 @@ Date: May 2006 #include #include -#include "gcc_cmdline.h" #include "armcc_cmdline.h" -#include "ms_cl_cmdline.h" -#include "ld_cmdline.h" -#include "bcc_cmdline.h" -#include "as_cmdline.h" #include "as86_cmdline.h" +#include "as_cmdline.h" +#include "bcc_cmdline.h" +#include "gcc_cmdline.h" +#include "ld_cmdline.h" +#include "ms_cl_cmdline.h" +#include "ms_link_cmdline.h" #include "armcc_mode.h" #include "as_mode.h" @@ -31,6 +32,7 @@ Date: May 2006 #include "gcc_mode.h" #include "ld_mode.h" #include "ms_cl_mode.h" +#include "ms_link_mode.h" std::string to_lower_string(const std::string &s) { @@ -65,15 +67,21 @@ int main(int argc, const char **argv) std::string base_name=get_base_name(argv[0], false); #endif - if(base_name=="goto-link" || base_name=="link" || - base_name=="goto-cl" || base_name=="cl") + if(base_name == "goto-cl" || base_name == "cl") { - // this is the Visual Studio personality + // this is the Visual Studio CL personality ms_cl_cmdlinet cmdline; cmdline.parse_env(); ms_cl_modet ms_cl_mode(cmdline, base_name); return ms_cl_mode.main(argc, argv); } + else if(base_name == "goto-link" || base_name == "link") + { + // this is the Visual Studio LINK personality + ms_link_cmdlinet cmdline; + ms_link_modet ms_link_mode(cmdline); + return ms_link_mode.main(argc, argv); + } else if(base_name=="goto-cw" || base_name=="goto-cw-link") { diff --git a/src/goto-cc/ms_link_cmdline.cpp b/src/goto-cc/ms_link_cmdline.cpp new file mode 100644 index 0000000000..315fd03094 --- /dev/null +++ b/src/goto-cc/ms_link_cmdline.cpp @@ -0,0 +1,368 @@ +/*******************************************************************\ + +Module: A special command line object for LINK options + +Author: Daniel Kroening + +\*******************************************************************/ + +/// \file +/// A special command line object for LINK options + +#include "ms_link_cmdline.h" + +#include +#include +#include +#include +#include + +#include + +/// parses the command line options into a cmdlinet +/// \par parameters: argument count, argument strings +/// \return none +const char *non_ms_link_options[]= +{ + "--help", + "--verbosity" +}; + +bool ms_link_cmdlinet::parse(const std::vector &options) +{ + for(std::size_t i = 0; i < options.size(); i++) + { + // is it a non-link option? + if(std::string(options[i], 0, 2) == "--") + { + process_non_link_option(options[i]); + + if(options[i] == "--verbosity") + { + if(i < options.size() - 1) + { + set(options[i], options[i + 1]); + i++; // skip ahead + } + } + } + else if(!options[i].empty() && options[i][0] == '@') + { + // potentially recursive + process_response_file(std::string(options[i], 1, std::string::npos)); + } + else + process_link_option(options[i]); + } + + return false; +} + +/// parses the command line options into a cmdlinet +/// \par parameters: argument count, argument strings +/// \return none +bool ms_link_cmdlinet::parse(int argc, const char **argv) +{ + // should really use "wide" argv from wmain() + + std::vector options; + + // skip argv[0] + for(int i = 1; i < argc; i++) + options.push_back(argv[i]); + + return parse(options); +} + +static std::istream &my_wgetline(std::istream &in, std::wstring &dest) +{ + // We should support this properly, + // but will just strip right now. + dest.clear(); + + while(in) + { + char ch1, ch2; + in.get(ch1); + in.get(ch2); + + if(!in) + { + if(!dest.empty()) + in.clear(); + break; + } + + if(ch1 == '\r') + { + // ignore + } + else if(ch1 == '\n') + { + in.clear(); + break; // line end + } + else + dest += wchar_t(ch1 + (ch2 << 8)); + } + + return in; +} + +/// \return none +void ms_link_cmdlinet::process_response_file(const std::string &file) +{ + std::ifstream infile(file); + + if(!infile) + { + std::cerr << "failed to open response file `" << file << "'\n"; + return; + } + + // these may be Unicode -- which is indicated by 0xff 0xfe + std::string line; + getline(infile, line); + if( + line.size() >= 2 && line[0] == static_cast(0xff) && + line[1] == static_cast(0xfe)) + { + // Unicode, UTF-16 little endian + +#if 1 + // Re-open -- should be using wifstream, + // but this isn't available everywhere. + std::ifstream infile2(file, std::ios::binary); + infile2.seekg(2); + std::wstring wline; + + while(my_wgetline(infile2, wline)) + process_response_file_line(narrow(wline)); // we UTF-8 it + +#else + + std::wifstream infile2(file, std::ios::binary); + std::wstring wline; + + while(std::getline(infile2, wline)) + process_response_file_line(narrow(wline)); // we UTF-8 it + +#endif + } + else if( + line.size() >= 3 && line[0] == static_cast(0xef) && + line[1] == static_cast(0xbb) && line[2] == static_cast(0xbf)) + { + // This is the UTF-8 BOM. We can proceed as usual, since + // we use UTF-8 internally. + infile.seekg(3); + + while(getline(infile, line)) + process_response_file_line(line); + } + else + { + // normal ASCII + infile.seekg(0); + while(getline(infile, line)) + process_response_file_line(line); + } +} + +/// \return none +void ms_link_cmdlinet::process_response_file_line(const std::string &line) +{ + // In a response file, multiple compiler options and source-code files can + // appear on one line. A single compiler-option specification must appear + // on one line (cannot span multiple lines). Response files can have + // comments that begin with the # symbol. + + if(line.empty()) + return; + if(line[0] == '#') + return; // comment + + std::vector options; + std::string option; + bool in_quotes = false; + for(std::size_t i = 0; i < line.size(); i++) + { + char ch = line[i]; + + if(ch == ' ' && !in_quotes) + { + if(!option.empty()) + options.push_back(option); + option.clear(); + } + else if(ch == '"') + { + in_quotes = !in_quotes; + } + else + option += ch; + } + + if(!option.empty()) + options.push_back(option); + + parse(options); +} + +/// \return none +void ms_link_cmdlinet::process_non_link_option(const std::string &s) +{ + set(s); + + for(const auto & opt : non_ms_link_options) + if(s == opt) + return; + + // unrecognized option + std::cout << "Warning: uninterpreted non-LINK option `" << s << "'\n"; +} + +const char *ms_link_options[] = { + "ALIGN", + "ALLOWBIND", + "ALLOWISOLATION", + "APPCONTAINER", + "ASSEMBLYDEBUG", + "ASSEMBLYLINKRESOURCE", + "ASSEMBLYMODULE", + "ASSEMBLYRESOURCE", + "BASE", + "CLRIMAGETYPE", + "CLRLOADEROPTIMIZATION", + "CLRSUPPORTLASTERROR", + "CLRTHREADATTRIBUTE", + "CLRUNMANAGEDCODECHECK", + "DEBUG", + "DEF", + "DEFAULTLIB", + "DELAY", + "DELAYLOAD", + "DELAYSIGN", + "DLL", + "DRIVER", + "DYNAMICBASE", + "ENTRY", + "ERRORREPORT", + "EXPORT", + "EXPORTPADMIN", + "FASTGENPROFILE", + "FIXED", + "FORCE", + "FUNCTIONPADMIN", + "GUARD", + "GENPROFILE", + "HEAP", + "HIGHENTROPYVA", + "IDLOUT", + "IGNORE", + "IGNOREIDL", + "IMPLIB", + "INCLUDE", + "INCREMENTAL", + "INTEGRITYCHECK", + "KERNEL", + "KEYCONTAINER", + "KEYFILE", + "LARGEADDRESSAWARE", + "LIBPATH", + "LTCG", + "MACHINE", + "MANIFEST", + "MANIFESTDEPENDENCY", + "MANIFESTFILE", + "MANIFESTINPUT", + "MANIFESTUAC", + "MAP", + "MAPINFO", + "MERGE", + "MIDL", + "NOASSEMBLY", + "NODEFAULTLIB", + "NOENTRY", + "NOIMPLIB", + "NOLOGO", + "NXCOMPAT", + "OPT", + "ORDER", + "OUT", + "PDB", + "PDBSTRIPPED", + "PROFILE", + "RELEASE", + "SAFESEH", + "SECTION", + "STACK", + "STUB", + "SUBSYSTEM", + "SWAPRUN", + "TLBID", + "TLBOUT", + "TIME", + "TSAWARE", + "USEPROFILE", + "VERBOSE", + "VERSION", + "WINMD", + "WINMDDELAYSIGN", + "WINMDFILE", + "WINMDKEYCONTAINER", + "WINMDKEYFILE", + "WHOLEARCHIVE", + "WX" +}; + +static std::string to_upper_string(const std::string &s) +{ + std::string result = s; + transform(result.begin(), result.end(), result.begin(), toupper); + return result; +} + +void ms_link_cmdlinet::process_link_option(const std::string &s) +{ + if(s == "") + return; + + if(s[0] != '/' && s[0] != '-') + { + args.push_back(s); + return; + } + + for(const std::string &ms_link_option : ms_link_options) + { + // These are case insensitive. + if( + to_upper_string(std::string(s, 1, std::string::npos)) == ms_link_option || + to_upper_string(std::string(s, 1, ms_link_option.size() + 1)) == ms_link_option + ':') + { + optionalt optnr = getoptnr(ms_link_option); + + if(!optnr.has_value()) + { + cmdlinet::optiont option; + option.islong = true; + option.optstring = ms_link_option; + option.optchar = 0; + options.push_back(option); + optnr = options.size() - 1; + } + + options[*optnr].isset = true; + + if(s.size() > ms_link_option.size() + 1) + options[*optnr].values.push_back( + std::string(s, ms_link_option.size() + 2, std::string::npos)); + + return; + } + } + + // unrecognized option + std::cout << "Warning: uninterpreted LINK option `" << s << "'\n"; +} diff --git a/src/goto-cc/ms_link_cmdline.h b/src/goto-cc/ms_link_cmdline.h new file mode 100644 index 0000000000..d6098bfc61 --- /dev/null +++ b/src/goto-cc/ms_link_cmdline.h @@ -0,0 +1,36 @@ +/*******************************************************************\ + +Module: A special command line object for LINK options + +Author: Daniel Kroening + +Date: July 2018 + +\*******************************************************************/ + +/// \file +/// A special command line object for LINK options + +#ifndef CPROVER_GOTO_CC_MS_LINK_CMDLINE_H +#define CPROVER_GOTO_CC_MS_LINK_CMDLINE_H + +#include "goto_cc_cmdline.h" + +class ms_link_cmdlinet : public goto_cc_cmdlinet +{ +public: + virtual bool parse(int, const char **); + + ms_link_cmdlinet() + { + } + +protected: + void process_non_link_option(const std::string &s); + void process_link_option(const std::string &s); + void process_response_file(const std::string &file); + void process_response_file_line(const std::string &line); + bool parse(const std::vector &); +}; + +#endif // CPROVER_GOTO_CC_MS_LINK_CMDLINE_H diff --git a/src/goto-cc/ms_link_mode.cpp b/src/goto-cc/ms_link_mode.cpp new file mode 100644 index 0000000000..8facd9bad8 --- /dev/null +++ b/src/goto-cc/ms_link_mode.cpp @@ -0,0 +1,84 @@ +/*******************************************************************\ + +Module: Visual Studio Link Mode + +Author: Daniel Kroening + +\*******************************************************************/ + +/// \file +/// Visual Studio Link Mode + +#include "ms_link_mode.h" + +#include + +#include +#include + +ms_link_modet::ms_link_modet(goto_cc_cmdlinet &_cmdline) + : goto_cc_modet(_cmdline, "link", message_handler) +{ +} + +/// does it. +int ms_link_modet::doit() +{ + if(cmdline.isset("help")) + { + help(); + return 0; + } + + eval_verbosity( + cmdline.get_value("verbosity"), messaget::M_ERROR, message_handler); + + compilet compiler(cmdline, message_handler, false); + + // determine actions to be undertaken + compiler.mode = compilet::LINK_LIBRARY; + + // get configuration + config.set(cmdline); + + compiler.object_file_extension = "obj"; + + if(cmdline.isset("LIBPATH")) + compiler.library_paths = cmdline.get_values("LIBPATH"); + // Don't add the system paths! + + if(cmdline.isset("OUT")) + { + // This must be a file, not a directory. + // If the option is given multiple times, the last instance wins. + const auto &values = cmdline.get_values("OUT"); + if(!values.empty()) + compiler.output_file_executable = values.back(); + } + else + { + // The first input file is used to determine the default + // name of the executable. + if(!cmdline.args.empty()) + compiler.output_file_executable = get_base_name(cmdline.args[0], true)+".exe"; + } + + // We now iterate over any input files + + for(const auto &arg : cmdline.parsed_argv) + if(arg.is_infile_name) + compiler.add_input_file(arg.arg); + + // do all the rest + if(compiler.doit()) + return 1; + + return 0; +} + +/// display command line help +void ms_link_modet::help_mode() +{ + std::cout << "goto-link understands the options of " + << "link plus the following.\n\n"; +} diff --git a/src/goto-cc/ms_link_mode.h b/src/goto-cc/ms_link_mode.h new file mode 100644 index 0000000000..a606b1c951 --- /dev/null +++ b/src/goto-cc/ms_link_mode.h @@ -0,0 +1,34 @@ +/*******************************************************************\ + +Module: Visual Studio Link Mode + +Author: Daniel Kroening + +Date: July 2018 + +\*******************************************************************/ + +/// \file +/// Visual Studio Link Mode + +#ifndef CPROVER_GOTO_CC_MS_LINK_MODE_H +#define CPROVER_GOTO_CC_MS_LINK_MODE_H + +#include "compile.h" +#include "goto_cc_mode.h" + +#include + +class ms_link_modet : public goto_cc_modet +{ +public: + int doit() final; + void help_mode() final; + + explicit ms_link_modet(goto_cc_cmdlinet &); + +protected: + console_message_handlert message_handler; +}; + +#endif // CPROVER_GOTO_CC_MS_LINK_MODE_H