aboutsummaryrefslogtreecommitdiffstats
path: root/solc/CommandLineInterface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'solc/CommandLineInterface.cpp')
-rw-r--r--solc/CommandLineInterface.cpp121
1 files changed, 80 insertions, 41 deletions
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index 8b331c75..e0c6a2b6 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -80,7 +80,6 @@ static string const g_strAstJson = "ast-json";
static string const g_strAstCompactJson = "ast-compact-json";
static string const g_strBinary = "bin";
static string const g_strBinaryRuntime = "bin-runtime";
-static string const g_strCloneBinary = "clone-bin";
static string const g_strCombinedJson = "combined-json";
static string const g_strCompactJSON = "compact-format";
static string const g_strContracts = "contracts";
@@ -128,7 +127,6 @@ static string const g_argAstCompactJson = g_strAstCompactJson;
static string const g_argAstJson = g_strAstJson;
static string const g_argBinary = g_strBinary;
static string const g_argBinaryRuntime = g_strBinaryRuntime;
-static string const g_argCloneBinary = g_strCloneBinary;
static string const g_argCombinedJson = g_strCombinedJson;
static string const g_argCompactJSON = g_strCompactJSON;
static string const g_argGas = g_strGas;
@@ -161,7 +159,6 @@ static set<string> const g_combinedJsonArgs
g_strAst,
g_strBinary,
g_strBinaryRuntime,
- g_strCloneBinary,
g_strCompactJSON,
g_strInterface,
g_strMetadata,
@@ -213,7 +210,6 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args)
g_argAstJson,
g_argBinary,
g_argBinaryRuntime,
- g_argCloneBinary,
g_argMetadata,
g_argNatspecUser,
g_argNatspecDev,
@@ -230,31 +226,21 @@ void CommandLineInterface::handleBinary(string const& _contract)
if (m_args.count(g_argBinary))
{
if (m_args.count(g_argOutputDir))
- createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", m_compiler->object(_contract).toHex());
+ createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", objectWithLinkRefsHex(m_compiler->object(_contract)));
else
{
cout << "Binary: " << endl;
- cout << m_compiler->object(_contract).toHex() << endl;
- }
- }
- if (m_args.count(g_argCloneBinary))
- {
- if (m_args.count(g_argOutputDir))
- createFile(m_compiler->filesystemFriendlyName(_contract) + ".clone_bin", m_compiler->cloneObject(_contract).toHex());
- else
- {
- cout << "Clone Binary: " << endl;
- cout << m_compiler->cloneObject(_contract).toHex() << endl;
+ cout << objectWithLinkRefsHex(m_compiler->object(_contract)) << endl;
}
}
if (m_args.count(g_argBinaryRuntime))
{
if (m_args.count(g_argOutputDir))
- createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", m_compiler->runtimeObject(_contract).toHex());
+ createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)));
else
{
cout << "Binary of the runtime part: " << endl;
- cout << m_compiler->runtimeObject(_contract).toHex() << endl;
+ cout << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << endl;
}
}
}
@@ -275,7 +261,7 @@ void CommandLineInterface::handleBytecode(string const& _contract)
{
if (m_args.count(g_argOpcodes))
handleOpcode(_contract);
- if (m_args.count(g_argBinary) || m_args.count(g_argCloneBinary) || m_args.count(g_argBinaryRuntime))
+ if (m_args.count(g_argBinary) || m_args.count(g_argBinaryRuntime))
handleBinary(_contract);
}
@@ -406,7 +392,18 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
{
auto eq = find(path.begin(), path.end(), '=');
if (eq != path.end())
- path = string(eq + 1, path.end());
+ {
+ if (auto r = CompilerStack::parseRemapping(path))
+ {
+ m_remappings.emplace_back(std::move(*r));
+ path = string(eq + 1, path.end());
+ }
+ else
+ {
+ cerr << "Invalid remapping: \"" << path << "\"." << endl;
+ return false;
+ }
+ }
else if (path == "-")
addStdin = true;
else
@@ -416,11 +413,11 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
{
if (!ignoreMissing)
{
- cerr << "\"" << infile << "\" is not found" << endl;
+ cerr << infile << " is not found." << endl;
return false;
}
else
- cerr << "\"" << infile << "\" is not found. Skipping." << endl;
+ cerr << infile << " is not found. Skipping." << endl;
continue;
}
@@ -429,16 +426,16 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
{
if (!ignoreMissing)
{
- cerr << "\"" << infile << "\" is not a valid file" << endl;
+ cerr << infile << " is not a valid file." << endl;
return false;
}
else
- cerr << "\"" << infile << "\" is not a valid file. Skipping." << endl;
+ cerr << infile << " is not a valid file. Skipping." << endl;
continue;
}
- m_sourceCodes[infile.string()] = dev::readFileAsString(infile.string());
+ m_sourceCodes[infile.generic_string()] = dev::readFileAsString(infile.string());
path = boost::filesystem::canonical(infile).string();
}
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
@@ -447,7 +444,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
m_sourceCodes[g_stdinFileName] = dev::readStandardInput();
if (m_sourceCodes.size() == 0)
{
- cerr << "No input files given. If you wish to use the standard input please specify \"-\" explicity." << endl;
+ cerr << "No input files given. If you wish to use the standard input please specify \"-\" explicitly." << endl;
return false;
}
@@ -485,9 +482,23 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
string addrString(lib.begin() + colon + 1, lib.end());
boost::trim(libName);
boost::trim(addrString);
+ if (addrString.substr(0, 2) == "0x")
+ addrString = addrString.substr(2);
+ if (addrString.empty())
+ {
+ cerr << "Empty address provided for library \"" << libName << "\": " << endl;
+ cerr << "Note that there should not be any whitespace after the colon." << endl;
+ return false;
+ }
+ else if (addrString.length() != 40)
+ {
+ cerr << "Invalid length for address for library \"" << libName << "\": " << addrString.length() << " instead of 40 characters." << endl;
+ return false;
+ }
if (!passesAddressChecksum(addrString, false))
{
- cerr << "Invalid checksum on library address \"" << libName << "\": " << addrString << endl;
+ cerr << "Invalid checksum on address for library \"" << libName << "\": " << addrString << endl;
+ cerr << "The correct checksum is " << dev::getChecksummedAddress(addrString) << endl;
return false;
}
bytes binAddr = fromHex(addrString);
@@ -572,7 +583,7 @@ Allowed options)",
g_argLibraries.c_str(),
po::value<vector<string>>()->value_name("libs"),
"Direct string or file containing library addresses. Syntax: "
- "<libraryName>: <address> [, or whitespace] ...\n"
+ "<libraryName>:<address> [, or whitespace] ...\n"
"Address is interpreted as a hex string optionally prefixed by 0x."
)
(
@@ -631,7 +642,6 @@ Allowed options)",
(g_argOpcodes.c_str(), "Opcodes of the contracts.")
(g_argBinary.c_str(), "Binary of the contracts in hex.")
(g_argBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.")
- (g_argCloneBinary.c_str(), "Binary of the clone contracts in hex.")
(g_argAbi.c_str(), "ABI specification of the contracts.")
(g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.")
(g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.")
@@ -724,7 +734,7 @@ bool CommandLineInterface::processInput()
return ReadCallback::Result{false, "Not a valid file."};
auto contents = dev::readFileAsString(canonicalPath.string());
- m_sourceCodes[path.string()] = contents;
+ m_sourceCodes[path.generic_string()] = contents;
return ReadCallback::Result{true, contents};
}
catch (Exception const& _exception)
@@ -740,13 +750,15 @@ bool CommandLineInterface::processInput()
if (m_args.count(g_argAllowPaths))
{
vector<string> paths;
- for (string const& path: boost::split(paths, m_args[g_argAllowPaths].as<string>(), boost::is_any_of(","))) {
+ for (string const& path: boost::split(paths, m_args[g_argAllowPaths].as<string>(), boost::is_any_of(",")))
+ {
auto filesystem_path = boost::filesystem::path(path);
// If the given path had a trailing slash, the Boost filesystem
// path will have it's last component set to '.'. This breaks
// path comparison in later parts of the code, so we need to strip
// it.
- if (filesystem_path.filename() == ".") {
+ if (filesystem_path.filename() == ".")
+ {
filesystem_path.remove_filename();
}
m_allowedDirectories.push_back(filesystem_path);
@@ -823,7 +835,7 @@ bool CommandLineInterface::processInput()
if (m_args.count(g_argMetadataLiteral) > 0)
m_compiler->useMetadataLiteralSources(true);
if (m_args.count(g_argInputFile))
- m_compiler->setRemappings(m_args[g_argInputFile].as<vector<string>>());
+ m_compiler->setRemappings(m_remappings);
for (auto const& sourceCode: m_sourceCodes)
m_compiler->addSource(sourceCode.first, sourceCode.second);
if (m_args.count(g_argLibraries))
@@ -910,8 +922,6 @@ void CommandLineInterface::handleCombinedJSON()
contractData[g_strBinary] = m_compiler->object(contractName).toHex();
if (requests.count(g_strBinaryRuntime))
contractData[g_strBinaryRuntime] = m_compiler->runtimeObject(contractName).toHex();
- if (requests.count(g_strCloneBinary))
- contractData[g_strCloneBinary] = m_compiler->cloneObject(contractName).toHex();
if (requests.count(g_strOpcodes))
contractData[g_strOpcodes] = solidity::disassemble(m_compiler->object(contractName).bytecode);
if (requests.count(g_strAsm))
@@ -984,12 +994,15 @@ void CommandLineInterface::handleAst(string const& _argStr)
for (auto const& sourceCode: m_sourceCodes)
asts.push_back(&m_compiler->ast(sourceCode.first));
map<ASTNode const*, eth::GasMeter::GasConsumption> gasCosts;
- // FIXME: shouldn't this be done for every contract?
- if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
- gasCosts = GasEstimator::breakToStatementLevel(
- GasEstimator(m_evmVersion).structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
+ for (auto const& contract : m_compiler->contractNames())
+ {
+ auto ret = GasEstimator::breakToStatementLevel(
+ GasEstimator(m_evmVersion).structuralEstimation(*m_compiler->runtimeAssemblyItems(contract), asts),
asts
);
+ for (auto const& it: ret)
+ gasCosts[it.first] += it.second;
+ }
bool legacyFormat = !m_args.count(g_argAstCompactJson);
if (m_args.count(g_argOutputDir))
@@ -1055,8 +1068,12 @@ bool CommandLineInterface::link()
{
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.
+ // This leaves 36 characters for the library identifier. The identifier used to
+ // be just the cropped or '_'-padded library name, but this changed to
+ // the cropped hex representation of the hash of the library name.
+ // We support both ways of linking here.
+ librariesReplacements["__" + eth::LinkerObject::libraryPlaceholder(name) + "__"] = library.second;
+
string replacement = "__";
for (size_t i = 0; i < placeholderSize - 4; ++i)
replacement.push_back(i < name.size() ? name[i] : '_');
@@ -1086,6 +1103,11 @@ bool CommandLineInterface::link()
cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl;
it += placeholderSize;
}
+ // Remove hints for resolved libraries.
+ for (auto const& library: m_libraries)
+ boost::algorithm::erase_all(src.second, "\n" + libraryPlaceholderHint(library.first));
+ while (!src.second.empty() && *prev(src.second.end()) == '\n')
+ src.second.resize(src.second.size() - 1);
}
return true;
}
@@ -1099,6 +1121,23 @@ void CommandLineInterface::writeLinkedFiles()
writeFile(src.first, src.second);
}
+string CommandLineInterface::libraryPlaceholderHint(string const& _libraryName)
+{
+ return "// " + eth::LinkerObject::libraryPlaceholder(_libraryName) + " -> " + _libraryName;
+}
+
+string CommandLineInterface::objectWithLinkRefsHex(eth::LinkerObject const& _obj)
+{
+ string out = _obj.toHex();
+ if (!_obj.linkReferences.empty())
+ {
+ out += "\n";
+ for (auto const& linkRef: _obj.linkReferences)
+ out += "\n" + libraryPlaceholderHint(linkRef.second);
+ }
+ return out;
+}
+
bool CommandLineInterface::assemble(
AssemblyStack::Language _language,
AssemblyStack::Machine _targetMachine