Microsoft LINK personality

This commit is contained in:
Daniel Kroening 2018-07-25 17:14:17 +01:00 committed by Michael Tautschnig
parent d9f9dd9d2a
commit 64fedd051b
6 changed files with 540 additions and 8 deletions

View File

@ -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) \

View File

@ -17,13 +17,14 @@ Date: May 2006
#include <util/unicode.h>
#include <util/get_base_name.h>
#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")
{

View File

@ -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 <cassert>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <util/unicode.h>
/// 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<std::string> &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<std::string> 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<char>(0xff) &&
line[1] == static_cast<char>(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<char>(0xef) &&
line[1] == static_cast<char>(0xbb) && line[2] == static_cast<char>(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<std::string> 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<std::size_t> 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";
}

View File

@ -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<std::string> &);
};
#endif // CPROVER_GOTO_CC_MS_LINK_CMDLINE_H

View File

@ -0,0 +1,84 @@
/*******************************************************************\
Module: Visual Studio Link Mode
Author: Daniel Kroening
\*******************************************************************/
/// \file
/// Visual Studio Link Mode
#include "ms_link_mode.h"
#include <iostream>
#include <util/config.h>
#include <util/get_base_name.h>
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";
}

View File

@ -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 <util/cout_message.h>
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