Microsoft LINK personality
This commit is contained in:
parent
d9f9dd9d2a
commit
64fedd051b
|
@ -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) \
|
||||
|
|
|
@ -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")
|
||||
{
|
||||
|
|
|
@ -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";
|
||||
}
|
|
@ -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
|
|
@ -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";
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue