aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-09-14 20:56:01 +0800
committerchriseth <c@ethdev.com>2015-09-14 20:56:01 +0800
commit9309b6aa82de6bbe7a93d34559b6cfca20c5978d (patch)
tree1457e0d1d8f5627c01c6082252f3050bc6a5dce3
parent4360e0459622e7843ca9f8d7fb5113da0b8a044e (diff)
parent70c0ed41290f3de001fed5b4f0f28993486ba445 (diff)
downloaddexon-solidity-9309b6aa82de6bbe7a93d34559b6cfca20c5978d.tar.gz
dexon-solidity-9309b6aa82de6bbe7a93d34559b6cfca20c5978d.tar.zst
dexon-solidity-9309b6aa82de6bbe7a93d34559b6cfca20c5978d.zip
Merge pull request #70 from chriseth/sol_libraries2
Commandline interface for linker.
-rw-r--r--libsolidity/CompilerStack.cpp10
-rw-r--r--libsolidity/CompilerStack.h7
-rw-r--r--libsolidity/Types.cpp7
-rw-r--r--solc/CommandLineInterface.cpp118
-rw-r--r--solc/CommandLineInterface.h12
5 files changed, 148 insertions, 6 deletions
diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp
index 3da982a4..70bb1b4c 100644
--- a/libsolidity/CompilerStack.cpp
+++ b/libsolidity/CompilerStack.cpp
@@ -181,6 +181,16 @@ eth::LinkerObject const& CompilerStack::compile(string const& _sourceCode, bool
return object();
}
+void CompilerStack::link(const std::map<string, h160>& _libraries)
+{
+ for (auto& contract: m_contracts)
+ {
+ contract.second.object.link(_libraries);
+ contract.second.runtimeObject.link(_libraries);
+ contract.second.cloneObject.link(_libraries);
+ }
+}
+
eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const
{
Contract const& currentContract = contract(_contractName);
diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h
index 8db8aff4..99e8af1a 100644
--- a/libsolidity/CompilerStack.h
+++ b/libsolidity/CompilerStack.h
@@ -96,9 +96,12 @@ public:
/// @returns the compiled linker object
eth::LinkerObject const& compile(std::string const& _sourceCode, bool _optimize = false);
- /// @returns the assembled bytecode for a contract (empty if it has to be linked or lacks implementation).
+ /// Inserts the given addresses into the linker objects of all compiled contracts.
+ void link(std::map<std::string, h160> const& _libraries);
+
+ /// @returns the assembled object for a contract.
eth::LinkerObject const& object(std::string const& _contractName = "") const;
- /// @returns the runtime bytecode for the contract (empty if it has to be linked or lacks implementation).
+ /// @returns the runtime object for the contract.
eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const;
/// @returns the bytecode of a contract that uses an already deployed contract via CALLCODE.
/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp
index 5bc7cd43..beb5becd 100644
--- a/libsolidity/Types.cpp
+++ b/libsolidity/Types.cpp
@@ -925,7 +925,10 @@ bool ContractType::operator==(Type const& _other) const
string ContractType::toString(bool) const
{
- return "contract " + string(m_super ? "super " : "") + m_contract.name();
+ return
+ string(m_contract.isLibrary() ? "library " : "contract ") +
+ string(m_super ? "super " : "") +
+ m_contract.name();
}
MemberList const& ContractType::members() const
@@ -971,7 +974,7 @@ MemberList const& ContractType::members() const
for (auto const& it: m_contract.interfaceFunctions())
members.push_back(MemberList::Member(
it.second->declaration().name(),
- it.second->asMemberFunction(false),
+ it.second->asMemberFunction(m_contract.isLibrary()),
&it.second->declaration()
));
m_members.reset(new MemberList(members));
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index c34ffee0..3d9c3f08 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -69,6 +69,7 @@ static string const g_argOpcodesStr = "opcodes";
static string const g_argNatspecDevStr = "devdoc";
static string const g_argNatspecUserStr = "userdoc";
static string const g_argAddStandard = "add-std";
+static string const g_stdinFileName = "<stdin>";
/// Possible arguments to for --combined-json
static set<string> const g_combinedJsonArgs{
@@ -282,6 +283,39 @@ void CommandLineInterface::handleGasEstimation(string const& _contract)
}
}
+bool CommandLineInterface::parseLibraryOption(string const& _input)
+{
+ namespace fs = boost::filesystem;
+ string data = fs::is_regular_file(_input) ? contentsString(_input) : _input;
+
+ vector<string> libraries;
+ boost::split(libraries, data, boost::is_space() || boost::is_any_of(","), boost::token_compress_on);
+ for (string const& lib: libraries)
+ if (!lib.empty())
+ {
+ auto colon = lib.find(':');
+ if (colon == string::npos)
+ {
+ cerr << "Colon separator missing in library address specifier \"" << lib << "\"" << endl;
+ return false;
+ }
+ string libName(lib.begin(), lib.begin() + colon);
+ string addrString(lib.begin() + colon + 1, lib.end());
+ boost::trim(libName);
+ boost::trim(addrString);
+ bytes binAddr = fromHex(addrString);
+ h160 address(binAddr, h160::AlignRight);
+ if (binAddr.size() > 20 || address == h160())
+ {
+ cerr << "Invalid address for library \"" << libName << "\": " << addrString << endl;
+ return false;
+ }
+ m_libraries[libName] = address;
+ }
+
+ return true;
+}
+
void CommandLineInterface::createFile(string const& _fileName, string const& _data)
{
namespace fs = boost::filesystem;
@@ -320,6 +354,13 @@ Allowed options)",
)
(g_argAddStandard.c_str(), "Add standard contracts.")
(
+ "libraries",
+ po::value<vector<string>>()->value_name("libs"),
+ "Direct string or file containing library addresses. Syntax: "
+ "<libraryName>: <address> [, or whitespace] ...\n"
+ "Address is interpreted as a hex string optionally prefixed by 0x."
+ )
+ (
"output-dir,o",
po::value<string>()->value_name("path"),
"If given, creates one file per component and contract/file at the specified directory."
@@ -329,7 +370,12 @@ Allowed options)",
po::value<string>()->value_name(boost::join(g_combinedJsonArgs, ",")),
"Output a single json document containing the specified information."
)
- (g_argGas.c_str(), "Print an estimate of the maximal gas usage for each function.");
+ (g_argGas.c_str(), "Print an estimate of the maximal gas usage for each function.")
+ (
+ "link",
+ "Switch to linker mode, ignoring all options apart from --libraries "
+ "and modify binaries in place."
+ );
po::options_description outputComponents("Output Components");
outputComponents.add_options()
(g_argAstStr.c_str(), "AST of all source files.")
@@ -402,7 +448,7 @@ bool CommandLineInterface::processInput()
while (!cin.eof())
{
getline(cin, s);
- m_sourceCodes["<stdin>"].append(s + '\n');
+ m_sourceCodes[g_stdinFileName].append(s + '\n');
}
}
else
@@ -424,6 +470,18 @@ bool CommandLineInterface::processInput()
m_sourceCodes[infile] = dev::contentsString(infile);
}
+ if (m_args.count("libraries"))
+ for (string const& library: m_args["libraries"].as<vector<string>>())
+ if (!parseLibraryOption(library))
+ return false;
+
+ if (m_args.count("link"))
+ {
+ // switch to linker mode
+ m_onlyLink = true;
+ return link();
+ }
+
m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0));
try
{
@@ -433,6 +491,7 @@ bool CommandLineInterface::processInput()
bool optimize = m_args.count("optimize") > 0;
unsigned runs = m_args["optimize-runs"].as<unsigned>();
m_compiler->compile(optimize, runs);
+ m_compiler->link(m_libraries);
}
catch (ParserError const& _exception)
{
@@ -602,6 +661,61 @@ void CommandLineInterface::handleAst(string const& _argStr)
void CommandLineInterface::actOnInput()
{
+ if (m_onlyLink)
+ writeLinkedFiles();
+ else
+ outputCompilationResults();
+}
+
+bool CommandLineInterface::link()
+{
+ 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)
+ {
+ cerr << "Error in binary object file " << src.first << " at position " << (insertStart - src.second.begin()) << endl;
+ return false;
+ }
+
+ string name(nameStart, nameEnd);
+ if (m_libraries.count(name))
+ {
+ string hexStr(toHex(m_libraries.at(name).asBytes()));
+ copy(hexStr.begin(), hexStr.end(), insertStart);
+ }
+ else
+ cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl;
+ }
+ }
+ return true;
+}
+
+void CommandLineInterface::writeLinkedFiles()
+{
+ for (auto const& src: m_sourceCodes)
+ if (src.first == g_stdinFileName)
+ cout << src.second << endl;
+ else
+ writeFile(src.first, src.second);
+}
+
+void CommandLineInterface::outputCompilationResults()
+{
handleCombinedJSON();
// do we need AST output?
diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h
index f79bc0be..2af5a5e9 100644
--- a/solc/CommandLineInterface.h
+++ b/solc/CommandLineInterface.h
@@ -46,6 +46,11 @@ public:
void actOnInput();
private:
+ bool link();
+ void writeLinkedFiles();
+
+ void outputCompilationResults();
+
void handleCombinedJSON();
void handleAst(std::string const& _argStr);
void handleBinary(std::string const& _contract);
@@ -56,16 +61,23 @@ private:
std::string const& _contract);
void handleGasEstimation(std::string const& _contract);
+ /// Tries to read from the file @a _input or interprets _input literally if that fails.
+ /// It then tries to parse the contents and appends to m_libraries.
+ bool parseLibraryOption(std::string const& _input);
/// Create a file in the given directory
/// @arg _fileName the name of the file
/// @arg _data to be written
void createFile(std::string const& _fileName, std::string const& _data);
+ bool m_onlyLink = false;
+
/// Compiler arguments variable map
boost::program_options::variables_map m_args;
/// map of input files to source code strings
std::map<std::string, std::string> m_sourceCodes;
+ /// map of library names to addresses
+ std::map<std::string, h160> m_libraries;
/// Solidity compiler stack
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
};