aboutsummaryrefslogtreecommitdiffstats
path: root/solc/CommandLineInterface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'solc/CommandLineInterface.cpp')
-rw-r--r--solc/CommandLineInterface.cpp123
1 files changed, 73 insertions, 50 deletions
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index 17ab5ba4..2013c506 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -65,7 +65,6 @@ namespace solidity
{
static string const g_argAbiStr = "abi";
-static string const g_argSolInterfaceStr = "interface";
static string const g_argSignatureHashes = "hashes";
static string const g_argGas = "gas";
static string const g_argAsmStr = "asm";
@@ -86,6 +85,8 @@ static set<string> const g_combinedJsonArgs{
"bin",
"bin-runtime",
"clone-bin",
+ "srcmap",
+ "srcmap-runtime",
"opcodes",
"abi",
"interface",
@@ -114,7 +115,6 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args)
return false;
for (string const& arg: {
g_argAbiStr,
- g_argSolInterfaceStr,
g_argSignatureHashes,
g_argNatspecUserStr,
g_argAstJson,
@@ -213,11 +213,6 @@ void CommandLineInterface::handleMeta(DocumentationType _type, string const& _co
suffix = ".abi";
title = "Contract JSON ABI";
break;
- case DocumentationType::ABISolidityInterface:
- argName = g_argSolInterfaceStr;
- suffix = "_interface.sol";
- title = "Contract Solidity ABI";
- break;
case DocumentationType::NatspecUser:
argName = g_argNatspecUserStr;
suffix = ".docuser";
@@ -308,21 +303,18 @@ void CommandLineInterface::handleFormal()
void CommandLineInterface::readInputFilesAndConfigureRemappings()
{
+ vector<string> inputFiles;
+ bool addStdin = false;
if (!m_args.count("input-file"))
- {
- string s;
- while (!cin.eof())
- {
- getline(cin, s);
- m_sourceCodes[g_stdinFileName].append(s + '\n');
- }
- }
+ addStdin = true;
else
for (string path: m_args["input-file"].as<vector<string>>())
{
auto eq = find(path.begin(), path.end(), '=');
if (eq != path.end())
path = string(eq + 1, path.end());
+ else if (path == "-")
+ addStdin = true;
else
{
auto infile = boost::filesystem::path(path);
@@ -343,6 +335,15 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
}
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
}
+ if (addStdin)
+ {
+ string s;
+ while (!cin.eof())
+ {
+ getline(cin, s);
+ m_sourceCodes[g_stdinFileName].append(s + '\n');
+ }
+ }
}
bool CommandLineInterface::parseLibraryOption(string const& _input)
@@ -397,9 +398,9 @@ bool CommandLineInterface::parseArguments(int _argc, char** _argv)
po::options_description desc(
R"(solc, the Solidity commandline compiler.
Usage: solc [options] [input_file...]
-Compiles the given Solidity input files (or the standard input if none given) and
-outputs the components specified in the options at standard output or in files in
-the output directory, if specified.
+Compiles the given Solidity input files (or the standard input if none given or
+"-" is used as a file name) and outputs the components specified in the options
+at standard output or in files in the output directory, if specified.
Example: solc --bin -o /tmp/solcoutput contract.sol
Allowed options)",
@@ -453,7 +454,6 @@ Allowed options)",
(g_argRuntimeBinaryStr.c_str(), "Binary of the runtime part of the contracts in hex.")
(g_argCloneBinaryStr.c_str(), "Binary of the clone contracts in hex.")
(g_argAbiStr.c_str(), "ABI specification of the contracts.")
- (g_argSolInterfaceStr.c_str(), "Solidity interface of the contracts.")
(g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.")
(g_argNatspecUserStr.c_str(), "Natspec user documentation of all contracts.")
(g_argNatspecDevStr.c_str(), "Natspec developer documentation of all contracts.")
@@ -471,7 +471,7 @@ Allowed options)",
try
{
po::command_line_parser cmdLineParser(_argc, _argv);
- cmdLineParser.options(allOptions).positional(filesPositions).allow_unregistered();
+ cmdLineParser.options(allOptions).positional(filesPositions);
po::store(cmdLineParser.run(), m_args);
}
catch (po::error const& _exception)
@@ -531,17 +531,17 @@ bool CommandLineInterface::processInput()
CompilerStack::ReadFileCallback fileReader = [this](string const& _path)
{
- auto boostPath = boost::filesystem::path(_path);
- if (!boost::filesystem::exists(boostPath))
+ auto path = boost::filesystem::path(_path);
+ if (!boost::filesystem::exists(path))
return CompilerStack::ReadFileResult{false, "File not found."};
- boostPath = boost::filesystem::canonical(boostPath);
+ auto canonicalPath = boost::filesystem::canonical(path);
bool isAllowed = false;
for (auto const& allowedDir: m_allowedDirectories)
{
// If dir is a prefix of boostPath, we are fine.
if (
- std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(boostPath.begin(), boostPath.end()) &&
- std::equal(allowedDir.begin(), allowedDir.end(), boostPath.begin())
+ std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) &&
+ std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin())
)
{
isAllowed = true;
@@ -550,17 +550,17 @@ bool CommandLineInterface::processInput()
}
if (!isAllowed)
return CompilerStack::ReadFileResult{false, "File outside of allowed directories."};
- else if (!boost::filesystem::is_regular_file(boostPath))
+ else if (!boost::filesystem::is_regular_file(canonicalPath))
return CompilerStack::ReadFileResult{false, "Not a valid file."};
else
{
- auto contents = dev::contentsString(boostPath.string());
- m_sourceCodes[boostPath.string()] = contents;
+ auto contents = dev::contentsString(canonicalPath.string());
+ m_sourceCodes[path.string()] = contents;
return CompilerStack::ReadFileResult{true, contents};
}
};
- m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0, fileReader));
+ m_compiler.reset(new CompilerStack(fileReader));
auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compiler->scanner(_sourceName); };
try
{
@@ -641,8 +641,6 @@ void CommandLineInterface::handleCombinedJSON()
for (string const& contractName: contracts)
{
Json::Value contractData(Json::objectValue);
- if (requests.count("interface"))
- contractData["interface"] = m_compiler->solidityInterface(contractName);
if (requests.count("abi"))
contractData["abi"] = m_compiler->interface(contractName);
if (requests.count("bin"))
@@ -658,6 +656,16 @@ void CommandLineInterface::handleCombinedJSON()
ostringstream unused;
contractData["asm"] = m_compiler->streamAssembly(unused, contractName, m_sourceCodes, true);
}
+ if (requests.count("srcmap"))
+ {
+ auto map = m_compiler->sourceMapping(contractName);
+ contractData["srcmap"] = map ? *map : "";
+ }
+ if (requests.count("srcmap-runtime"))
+ {
+ auto map = m_compiler->runtimeSourceMapping(contractName);
+ contractData["srcmap-runtime"] = map ? *map : "";
+ }
if (requests.count("devdoc"))
contractData["devdoc"] = m_compiler->metadata(contractName, DocumentationType::NatspecDev);
if (requests.count("userdoc"))
@@ -665,12 +673,22 @@ void CommandLineInterface::handleCombinedJSON()
output["contracts"][contractName] = contractData;
}
+ bool needsSourceList = requests.count("ast") || requests.count("srcmap") || requests.count("srcmap-runtime");
+ if (needsSourceList)
+ {
+ // Indices into this array are used to abbreviate source names in source locations.
+ output["sourceList"] = Json::Value(Json::arrayValue);
+
+ for (auto const& source: m_compiler->sourceNames())
+ output["sourceList"].append(source);
+ }
+
if (requests.count("ast"))
{
output["sources"] = Json::Value(Json::objectValue);
for (auto const& sourceCode: m_sourceCodes)
{
- ASTJsonConverter converter(m_compiler->ast(sourceCode.first));
+ ASTJsonConverter converter(m_compiler->ast(sourceCode.first), m_compiler->sourceIndices());
output["sources"][sourceCode.first] = Json::Value(Json::objectValue);
output["sources"][sourceCode.first]["AST"] = converter.json();
}
@@ -760,37 +778,43 @@ void CommandLineInterface::actOnInput()
bool CommandLineInterface::link()
{
+ // Map from how the libraries will be named inside the bytecode to their addresses.
+ map<string, h160> librariesReplacements;
+ int const placeholderSize = 40; // 20 bytes or 40 hex characters
+ for (auto const& library: m_libraries)
+ {
+ string const& name = library.first;
+ // Library placeholders are 40 hex digits (20 bytes) that start and end with '__'.
+ // This leaves 36 characters for the library name, while too short library names are
+ // padded on the right with '_' and too long names are truncated.
+ string replacement = "__";
+ for (size_t i = 0; i < placeholderSize - 4; ++i)
+ replacement.push_back(i < name.size() ? name[i] : '_');
+ replacement += "__";
+ librariesReplacements[replacement] = library.second;
+ }
for (auto& src: m_sourceCodes)
{
auto end = src.second.end();
for (auto it = src.second.begin(); it != end;)
{
while (it != end && *it != '_') ++it;
- auto insertStart = it;
- while (it != end && *it == '_') ++it;
- auto nameStart = it;
- while (it != end && *it != '_') ++it;
- auto nameEnd = it;
- while (it != end && *it == '_') ++it;
- auto insertEnd = it;
-
- if (insertStart == end)
- break;
-
- if (insertEnd - insertStart != 40)
+ if (it == end) break;
+ if (end - it < placeholderSize)
{
- cerr << "Error in binary object file " << src.first << " at position " << (insertStart - src.second.begin()) << endl;
+ cerr << "Error in binary object file " << src.first << " at position " << (end - src.second.begin()) << endl;
return false;
}
- string name(nameStart, nameEnd);
- if (m_libraries.count(name))
+ string name(it, it + placeholderSize);
+ if (librariesReplacements.count(name))
{
- string hexStr(toHex(m_libraries.at(name).asBytes()));
- copy(hexStr.begin(), hexStr.end(), insertStart);
+ string hexStr(toHex(librariesReplacements.at(name).asBytes()));
+ copy(hexStr.begin(), hexStr.end(), it);
}
else
cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl;
+ it += placeholderSize;
}
}
return true;
@@ -879,7 +903,6 @@ void CommandLineInterface::outputCompilationResults()
handleBytecode(contract);
handleSignatureHashes(contract);
handleMeta(DocumentationType::ABIInterface, contract);
- handleMeta(DocumentationType::ABISolidityInterface, contract);
handleMeta(DocumentationType::NatspecDev, contract);
handleMeta(DocumentationType::NatspecUser, contract);
} // end of contracts iteration