mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Detailed documentation for path resolution in imports, including remappings, base path and standard input
This commit is contained in:
parent
215bbe2e6d
commit
5e3788874b
@ -165,6 +165,7 @@ Contents
|
|||||||
security-considerations.rst
|
security-considerations.rst
|
||||||
smtchecker.rst
|
smtchecker.rst
|
||||||
resources.rst
|
resources.rst
|
||||||
|
path-resolution.rst
|
||||||
yul.rst
|
yul.rst
|
||||||
style-guide.rst
|
style-guide.rst
|
||||||
common-patterns.rst
|
common-patterns.rst
|
||||||
|
@ -163,7 +163,7 @@ The component does not yet support all features of the Solidity language and
|
|||||||
likely outputs many warnings. In case it reports unsupported features, the
|
likely outputs many warnings. In case it reports unsupported features, the
|
||||||
analysis may not be fully sound.
|
analysis may not be fully sound.
|
||||||
|
|
||||||
.. index:: source file, ! import, module
|
.. index:: source file, ! import, module, source unit
|
||||||
|
|
||||||
.. _import:
|
.. _import:
|
||||||
|
|
||||||
@ -184,6 +184,7 @@ At a global level, you can use import statements of the following form:
|
|||||||
|
|
||||||
import "filename";
|
import "filename";
|
||||||
|
|
||||||
|
The ``filename`` part is called an *import path*.
|
||||||
This statement imports all global symbols from "filename" (and symbols imported there) into the
|
This statement imports all global symbols from "filename" (and symbols imported there) into the
|
||||||
current global scope (different than in ES6 but backwards-compatible for Solidity).
|
current global scope (different than in ES6 but backwards-compatible for Solidity).
|
||||||
This form is not recommended for use, because it unpredictably pollutes the namespace.
|
This form is not recommended for use, because it unpredictably pollutes the namespace.
|
||||||
@ -216,101 +217,34 @@ the code below creates new global symbols ``alias`` and ``symbol2`` which refere
|
|||||||
|
|
||||||
import {symbol1 as alias, symbol2} from "filename";
|
import {symbol1 as alias, symbol2} from "filename";
|
||||||
|
|
||||||
Paths
|
.. index:: virtual filesystem, source unit name, import; path, filesystem path, import callback, Remix IDE
|
||||||
-----
|
|
||||||
|
|
||||||
In the above, ``filename`` is always treated as a path with ``/`` as directory separator,
|
Import Paths
|
||||||
and ``.`` as the current and ``..`` as the parent directory. When ``.`` or ``..`` is followed by a character except ``/``,
|
------------
|
||||||
it is not considered as the current or the parent directory.
|
|
||||||
All path names are treated as absolute paths unless they start with the current ``.`` or the parent directory ``..``.
|
|
||||||
|
|
||||||
To import a file ``filename`` from the same directory as the current file, use ``import "./filename" as symbolName;``.
|
In order to be able to support reproducible builds on all platforms, the Solidity compiler has to
|
||||||
If you use ``import "filename" as symbolName;`` instead, a different file could be referenced
|
abstract away the details of the filesystem where source files are stored.
|
||||||
(in a global "include directory").
|
For this reason import paths do not refer directly to files in the host filesystem.
|
||||||
|
Instead the compiler maintains an internal database (*virtual filesystem* or *VFS* for short) where
|
||||||
|
each source unit is assigned a unique *source unit name* which is an opaque and unstructured identifier.
|
||||||
|
The import path specified in an import statement is translated into a source unit name and used to
|
||||||
|
find the corresponding source unit in this database.
|
||||||
|
|
||||||
It depends on the compiler (see :ref:`import-compiler`) how to actually resolve the paths.
|
Using the :ref:`Standard JSON <compiler-api>` API it is possible to directly provide the names and
|
||||||
In general, the directory hierarchy does not need to strictly map onto your local
|
content of all the source files as a part of the compiler input.
|
||||||
filesystem, and the path can also map to resources such as ipfs, http or git.
|
In this case source unit names are truly arbitrary.
|
||||||
|
If, however, you want the compiler to automatically find and load source code into the VFS, your
|
||||||
|
source unit names need to be structured in a way that makes it possible for an :ref:`import callback
|
||||||
|
<import-callback>` to locate them.
|
||||||
|
When using the command-line compiler the default import callback supports only loading source code
|
||||||
|
from the host filesystem, which means that your source unit names must be paths.
|
||||||
|
Some environments provide custom callbacks that are more versatile.
|
||||||
|
For example the `Remix IDE <https://remix.ethereum.org/>`_ provides one that
|
||||||
|
lets you `import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry
|
||||||
|
<https://remix-ide.readthedocs.io/en/latest/import.html>`_.
|
||||||
|
|
||||||
.. note::
|
For a complete description of the virtual filesystem and the path resolution logic used by the
|
||||||
Always use relative imports like ``import "./filename.sol";`` and avoid
|
compiler see :ref:`Path Resolution <path-resolution>`.
|
||||||
using ``..`` in path specifiers. In the latter case, it is probably better to use
|
|
||||||
global paths and set up remappings as explained below.
|
|
||||||
|
|
||||||
.. _import-compiler:
|
|
||||||
|
|
||||||
Use in Actual Compilers
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
When invoking the compiler, you can specify how to discover the first element
|
|
||||||
of a path, and also path prefix remappings. For
|
|
||||||
example you can setup a remapping so that everything imported from the virtual
|
|
||||||
directory ``github.com/ethereum/dapp-bin/library`` would actually be read from
|
|
||||||
your local directory ``/usr/local/dapp-bin/library``.
|
|
||||||
If multiple remappings apply, the one with the longest key is tried first.
|
|
||||||
An empty prefix is not allowed. The remappings can depend on a context,
|
|
||||||
which allows you to configure packages to import e.g., different versions of a
|
|
||||||
library of the same name.
|
|
||||||
|
|
||||||
**solc**:
|
|
||||||
|
|
||||||
For solc (the commandline compiler), you provide these path remappings as
|
|
||||||
``context:prefix=target`` arguments, where both the ``context:`` and the
|
|
||||||
``=target`` parts are optional (``target`` defaults to ``prefix`` in this
|
|
||||||
case). All remapping values that are regular files are compiled (including
|
|
||||||
their dependencies).
|
|
||||||
|
|
||||||
This mechanism is backwards-compatible (as long
|
|
||||||
as no filename contains ``=`` or ``:``) and thus not a breaking change. All
|
|
||||||
files in or below the ``context`` directory that import a file that starts with
|
|
||||||
``prefix`` are redirected by replacing ``prefix`` by ``target``.
|
|
||||||
|
|
||||||
For example, if you clone ``github.com/ethereum/dapp-bin/`` locally to
|
|
||||||
``/usr/local/dapp-bin``, you can use the following in your source file:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
|
|
||||||
|
|
||||||
Then run the compiler:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol
|
|
||||||
|
|
||||||
As a more complex example, suppose you rely on a module that uses an old
|
|
||||||
version of dapp-bin that you checked out to ``/usr/local/dapp-bin_old``, then you can run:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
solc module1:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ \
|
|
||||||
module2:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin_old/ \
|
|
||||||
source.sol
|
|
||||||
|
|
||||||
This means that all imports in ``module2`` point to the old version but imports
|
|
||||||
in ``module1`` point to the new version.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
``solc`` only allows you to include files from certain directories. They have
|
|
||||||
to be in the directory (or subdirectory) of one of the explicitly specified
|
|
||||||
source files or in the directory (or subdirectory) of a remapping target. If
|
|
||||||
you want to allow direct absolute includes, add the remapping ``/=/``.
|
|
||||||
|
|
||||||
If there are multiple remappings that lead to a valid file, the remapping
|
|
||||||
with the longest common prefix is chosen.
|
|
||||||
|
|
||||||
**Remix**:
|
|
||||||
|
|
||||||
`Remix <https://remix.ethereum.org/>`_ provides an automatic remapping for
|
|
||||||
GitHub and automatically retrieves the file over the network. You can import
|
|
||||||
the iterable mapping as above, e.g.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
|
|
||||||
|
|
||||||
Remix may add other source code providers in the future.
|
|
||||||
|
|
||||||
.. index:: ! comment, natspec
|
.. index:: ! comment, natspec
|
||||||
|
|
||||||
|
484
docs/path-resolution.rst
Normal file
484
docs/path-resolution.rst
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
.. _path-resolution:
|
||||||
|
|
||||||
|
**********************
|
||||||
|
Import Path Resolution
|
||||||
|
**********************
|
||||||
|
|
||||||
|
In order to be able to support reproducible builds on all platforms, the Solidity compiler has to
|
||||||
|
abstract away the details of the filesystem where source files are stored.
|
||||||
|
Paths used in imports must work the same way everywhere while the command-line interface must be
|
||||||
|
able to work with platform-specific paths to provide good user experience.
|
||||||
|
This section aims to explain in detail how Solidity reconciles these requirements.
|
||||||
|
|
||||||
|
.. index:: ! virtual filesystem, ! VFS, ! source unit name
|
||||||
|
.. _virtual-filesystem:
|
||||||
|
|
||||||
|
Virtual Filesystem
|
||||||
|
==================
|
||||||
|
|
||||||
|
The compiler maintains an internal database (*virtual filesystem* or *VFS* for short) where each
|
||||||
|
source unit is assigned a unique *source unit name* which is an opaque and unstructured identifier.
|
||||||
|
When you use the :ref:`import statement <import>`, you specify an *import path* that references a
|
||||||
|
source unit name.
|
||||||
|
|
||||||
|
.. index:: ! import callback, ! Host Filesystem Loader
|
||||||
|
.. _import-callback:
|
||||||
|
|
||||||
|
Import Callback
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The VFS is initially populated only with files the compiler has received as input.
|
||||||
|
Additional files can be loaded during compilation using an *import callback*, which is different
|
||||||
|
depending on the type of compiler you use (see below).
|
||||||
|
If the compiler does not find any source unit name matching the import path in the VFS, it invokes
|
||||||
|
the callback, which is responsible for obtaining the source code to be placed under that name.
|
||||||
|
An import callback is free to interpret source unit names in an arbitrary way, not just as paths.
|
||||||
|
If there is no callback available when one is needed or if it fails to locate the source code,
|
||||||
|
compilation fails.
|
||||||
|
|
||||||
|
The command-line compiler provides the *Host Filesystem Loader* - a rudimentary callback
|
||||||
|
that interprets a source unit name as a path in the local filesystem.
|
||||||
|
The `JavaScript interface <https://github.com/ethereum/solc-js>`_ does not provide any by default,
|
||||||
|
but one can be provided by the user.
|
||||||
|
This mechanism can be used to obtain source code from locations other then the local filesystem
|
||||||
|
(which may not even be accessible, e.g. when the compiler is running in a browser).
|
||||||
|
For example the `Remix IDE <https://remix.ethereum.org/>`_ provides a versatile callback that
|
||||||
|
lets you `import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry
|
||||||
|
<https://remix-ide.readthedocs.io/en/latest/import.html>`_.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Host Filesystem Loader's file lookup is platform-dependent.
|
||||||
|
For example backslashes in a source unit name can be interpreted as directory separators or not
|
||||||
|
and the lookup can be case-sensitive or not, depending on the underlying platform.
|
||||||
|
|
||||||
|
For portability it is recommended to avoid using import paths that will work correctly only
|
||||||
|
with a specific import callback or only on one platform.
|
||||||
|
For example you should always use forward slashes since they work as path separators also on
|
||||||
|
platforms that support backslashes.
|
||||||
|
|
||||||
|
Initial Content of the Virtual Filesystem
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
The initial content of the VFS depends on how you invoke the compiler:
|
||||||
|
|
||||||
|
#. **solc / command-line interface**
|
||||||
|
|
||||||
|
When you compile a file using the command-line interface of the compiler, you provide one or
|
||||||
|
more paths to files containing Solidity code:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc contract.sol /usr/local/dapp-bin/token.sol
|
||||||
|
|
||||||
|
The source unit name of a file loaded this way is simply the specified path after shell expansion
|
||||||
|
and with platform-specific separators converted to forward slashes.
|
||||||
|
|
||||||
|
.. index:: standard JSON
|
||||||
|
|
||||||
|
#. **Standard JSON**
|
||||||
|
|
||||||
|
When using the :ref:`Standard JSON <compiler-api>` API (via either the `JavaScript interface
|
||||||
|
<https://github.com/ethereum/solc-js>`_ or the ``--standard-json`` command-line option)
|
||||||
|
you provide input in JSON format, containing, among other things, the content of all your source
|
||||||
|
files:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"contract.sol": {
|
||||||
|
"content": "import \"./util.sol\";\ncontract C {}"
|
||||||
|
},
|
||||||
|
"util.sol": {
|
||||||
|
"content": "library Util {}"
|
||||||
|
},
|
||||||
|
"/usr/local/dapp-bin/token.sol": {
|
||||||
|
"content": "contract Token {}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {"outputSelection": {"*": { "*": ["metadata", "evm.bytecode"]}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
The ``sources`` dictionary becomes the initial content of the virtual filesystem and its keys
|
||||||
|
are used as source unit names.
|
||||||
|
|
||||||
|
#. **Standard JSON (via import callback)**
|
||||||
|
|
||||||
|
With Standard JSON it is also possible to tell the compiler to use the import callback to obtain
|
||||||
|
the source code:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"/usr/local/dapp-bin/token.sol": {
|
||||||
|
"urls": [
|
||||||
|
"/projects/mytoken.sol",
|
||||||
|
"https://example.com/projects/mytoken.sol"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {"outputSelection": {"*": { "*": ["metadata", "evm.bytecode"]}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
If an import callback is available, the compiler will give it the strings specified in
|
||||||
|
``urls`` one by one, until one is loaded successfully or the end of the list is reached.
|
||||||
|
|
||||||
|
The source unit names are determined the same way as when using ``content`` - they are keys of
|
||||||
|
the ``sources`` dictionary and the content of ``urls`` does not affect them in any way.
|
||||||
|
|
||||||
|
.. index:: standard input, stdin, <stdin>
|
||||||
|
|
||||||
|
#. **Standard input**
|
||||||
|
|
||||||
|
On the command line it is also possible to provide the source by sending it to compiler's
|
||||||
|
standard input:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
echo 'import "./util.sol"; contract C {}' | solc -
|
||||||
|
|
||||||
|
``-`` used as one of the arguments instructs the compiler to place the content of the standard
|
||||||
|
input in the virtual filesystem under a special source unit name: ``<stdin>``.
|
||||||
|
|
||||||
|
Once the VFS is initialized, additional files can still be added to it only through the import
|
||||||
|
callback.
|
||||||
|
|
||||||
|
.. index:: ! import; path
|
||||||
|
|
||||||
|
Imports
|
||||||
|
=======
|
||||||
|
|
||||||
|
The import statement specifies an *import path*.
|
||||||
|
Based on how the import path is specified, we can divide imports into two categories:
|
||||||
|
|
||||||
|
- :ref:`Direct imports <direct-imports>`, where you specify the full source unit name directly.
|
||||||
|
- :ref:`Relative imports <relative-imports>`, where you specify a path starting with ``./`` or ``../``
|
||||||
|
to be combined with the source unit name of the importing file.
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: contracts/contract.sol
|
||||||
|
|
||||||
|
import "./math/math.sol";
|
||||||
|
import "contracts/tokens/token.sol";
|
||||||
|
|
||||||
|
In the above ``./math/math.sol`` and ``contracts/tokens/token.sol`` are import paths while the
|
||||||
|
source unit names they translate to are ``contracts/math/math.sol`` and ``contracts/tokens/token.sol``
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
.. index:: ! direct import, import; direct
|
||||||
|
.. _direct-imports:
|
||||||
|
|
||||||
|
Direct Imports
|
||||||
|
--------------
|
||||||
|
|
||||||
|
An import that does not start with ``./`` or ``../`` is a *direct import*.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
import "/project/lib/util.sol"; // source unit name: /project/lib/util.sol
|
||||||
|
import "lib/util.sol"; // source unit name: lib/util.sol
|
||||||
|
import "@openzeppelin/address.sol"; // source unit name: @openzeppelin/address.sol
|
||||||
|
import "https://example.com/token.sol"; // source unit name: https://example.com/token.sol
|
||||||
|
|
||||||
|
After applying any :ref:`import remappings <import-remapping>` the import path simply becomes the
|
||||||
|
source unit name.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
A source unit name is just an identifier and even if its value happens to look like a path, it
|
||||||
|
is not subject to the normalization rules you would typically expect in a shell.
|
||||||
|
Any ``/./`` or ``/../`` seguments or sequences of multiple slashes remain a part of it.
|
||||||
|
When the source is provided via Standard JSON interface it is entirely possible to associate
|
||||||
|
different content with source unit names that would refer to the same file on disk.
|
||||||
|
|
||||||
|
When the source is not available in the virtual filesystem, the compiler passes the source unit name
|
||||||
|
to the import callback.
|
||||||
|
The Host Filesystem Loader will attempt to use it as a path and look up the file on disk.
|
||||||
|
At this point the platform-specific normalization rules kick in and names that were considered
|
||||||
|
different in the VFS may actually result in the same file being loaded.
|
||||||
|
For example ``/project/lib/math.sol`` and ``/project/lib/../lib///math.sol`` are considered
|
||||||
|
completely different in the VFS on disk refer to the same file.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Even if an import callback ends up loading source code for two different source unit names from
|
||||||
|
the same file on disk, the compiler will still see them as separate source units.
|
||||||
|
It is the source unit name that matters, not the physical location of the code.
|
||||||
|
|
||||||
|
.. index:: ! relative import, ! import; relative
|
||||||
|
.. _relative-imports:
|
||||||
|
|
||||||
|
Relative Imports
|
||||||
|
----------------
|
||||||
|
|
||||||
|
An import starting with ``./`` or ``../`` is a *relative import*.
|
||||||
|
Such imports specify a path relative to the source unit name of the importing source unit:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: /project/lib/math.sol
|
||||||
|
|
||||||
|
import "./util.sol" as util; // source unit name: /project/lib/util.sol
|
||||||
|
import "../token.sol" as token; // source unit name: /project/token.sol
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: lib/math.sol
|
||||||
|
|
||||||
|
import "./util.sol" as util; // source unit name: lib/util.sol
|
||||||
|
import "../token.sol" as token; // source unit name: token.sol
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Relative imports **always** start with ``./`` or ``../`` so ``import "util.sol"``, unlike
|
||||||
|
``import "./util.sol"``, is a direct import.
|
||||||
|
While both paths would be considered relative in the host filesystem, ``util.sol`` is actually
|
||||||
|
absolute in the VFS.
|
||||||
|
|
||||||
|
Let us define a *path segment* as any non-empty part of the path that does not contain a separator
|
||||||
|
and is bounded by two path separators.
|
||||||
|
A separator is a forward slash or the beginning/end of the string.
|
||||||
|
For example in ``./abc/..//`` there are three path segments: ``.``, ``abc`` and ``..``.
|
||||||
|
|
||||||
|
The compiler computes a source unit name from the import path in the following way:
|
||||||
|
|
||||||
|
1. First a prefix is computed
|
||||||
|
|
||||||
|
- Prefix is initialized with the source unit name of the importing source unit.
|
||||||
|
- The last path segment with preceding slashes is removed from the prefix.
|
||||||
|
- Then, the leading part of the normalized import path, consisting only of ``/`` and ``.``
|
||||||
|
characters is considered.
|
||||||
|
For every ``..`` segment found in this part the last path segment with preceding slashes is
|
||||||
|
removed from the prefix.
|
||||||
|
|
||||||
|
2. Then the prefix is prepended to the normalized import path.
|
||||||
|
If the prefix is non-empty, a single slash is inserted between it and the import path.
|
||||||
|
|
||||||
|
The removal of the last path segment with preceding slashes is understood to
|
||||||
|
work as follows:
|
||||||
|
|
||||||
|
1. Everything past the last slash is removed (i.e. ``a/b//c.sol`` becomes ``a/b//``).
|
||||||
|
2. All trailing slashes are removed (i.e. ``a/b//`` becomes ``a/b``).
|
||||||
|
|
||||||
|
The normalization rules are the same as for UNIX paths, namely:
|
||||||
|
|
||||||
|
- All the internal ``.`` segments are removed.
|
||||||
|
- Every internal ``..`` segment backtracks one level up in the hierarchy.
|
||||||
|
- Multiple slashes are squashed into a single one.
|
||||||
|
|
||||||
|
Note that normalization is performed only on the import path.
|
||||||
|
The source unit name of the importing module that is used for the prefix remains unnormalized.
|
||||||
|
This ensures that the ``protocol://`` part does not turn into ``protocol:/`` if the importing file
|
||||||
|
is identified with a URL.
|
||||||
|
|
||||||
|
If your import paths are already normalized, you can expect the above algorithm to produce very
|
||||||
|
intuitive results.
|
||||||
|
Here are some examples of what you can expect if they are not:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: lib/src/../contract.sol
|
||||||
|
|
||||||
|
import "./util/./util.sol"; // source unit name: lib/src/../util/util.sol
|
||||||
|
import "./util//util.sol"; // source unit name: lib/src/../util/util.sol
|
||||||
|
import "../util/../array/util.sol"; // source unit name: lib/src/array/util.sol
|
||||||
|
import "../.././../util.sol"; // source unit name: util.sol
|
||||||
|
import "../../.././../util.sol"; // source unit name: util.sol
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The use of relative imports containing leading ``..`` segments is not recommended.
|
||||||
|
The same effect can be achieved in a more reliable way by using direct imports with
|
||||||
|
:ref:`base path <base-path>` and :ref:`import remapping <import-remapping>`.
|
||||||
|
|
||||||
|
.. index:: ! base path, --base-path
|
||||||
|
.. _base-path:
|
||||||
|
|
||||||
|
Base Path
|
||||||
|
=========
|
||||||
|
|
||||||
|
The base path specifies the directory that the Host Filesystem Loader will load files from.
|
||||||
|
It is simply prepended to a source unit name before the filesystem lookup is performed.
|
||||||
|
|
||||||
|
By default the base path is empty, which leaves the source unit name unchanged.
|
||||||
|
When the source unit name is a relative path, this results in the file being looked up in the
|
||||||
|
directory the compiler has been invoked from.
|
||||||
|
It is also the only value that results in absolute paths in source unit names being actually
|
||||||
|
interpreted as absolute paths on disk.
|
||||||
|
|
||||||
|
If the base path itself is relative, it is also interpreted as relative to the current working
|
||||||
|
directory of the compiler.
|
||||||
|
|
||||||
|
.. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target
|
||||||
|
.. _import-remapping:
|
||||||
|
|
||||||
|
Import Remapping
|
||||||
|
================
|
||||||
|
|
||||||
|
Import remapping allows you to redirect imports to a different location in the virtual filesystem.
|
||||||
|
The mechanism works by changing the translation between import paths and source unit names.
|
||||||
|
For example you can set up a remapping so that any import from the virtual directory
|
||||||
|
``github.com/ethereum/dapp-bin/library/`` would be seen as an import from ``dapp-bin/library/`` instead.
|
||||||
|
|
||||||
|
You can limit the scope of a remapping by specifying a *context*.
|
||||||
|
This allows creating remappings that apply only to imports located in a specific library or a specific file.
|
||||||
|
Without a context a remapping is applied to every matching import in all the files in the virtual
|
||||||
|
filesystem.
|
||||||
|
|
||||||
|
Import remappings have the form of ``context:prefix=target``:
|
||||||
|
|
||||||
|
- ``context`` must match the beginning of the source unit name of the file containing the import.
|
||||||
|
- ``prefix`` must match the beginning of the source unit name resulting from the import.
|
||||||
|
- ``target`` is the value the prefix is replaced with.
|
||||||
|
|
||||||
|
For example, if you clone https://github.com/ethereum/dapp-bin/ locally to ``/project/dapp-bin``
|
||||||
|
and run the compiler with:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc github.com/ethereum/dapp-bin/=dapp-bin/ --base-path /project source.sol
|
||||||
|
|
||||||
|
you can use the following in your source file:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
import "github.com/ethereum/dapp-bin/library/math.sol"; // source unit name: dapp-bin/library/math.sol
|
||||||
|
|
||||||
|
The compiler will look for the file in the VFS under ``dapp-bin/library/math.sol``.
|
||||||
|
If the file is not available there, the source unit name will be passed to the Host Filesystem
|
||||||
|
Loader, which will then look in ``/project/dapp-bin/library/iterable_mapping.sol``.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Information about remappings is stored in contract metadata.
|
||||||
|
Since the binary produced by the compiler has a hash of the metadata embedded in it, any
|
||||||
|
modification to the remappings will result in different bytecode.
|
||||||
|
|
||||||
|
For this reason you should be careful not to include any local information in remapping targets.
|
||||||
|
For example if your library is located in ``/home/user/packages/mymath/math.sol``, a remapping
|
||||||
|
like ``@math/=/home/user/packages/mymath/`` would result in your home directory being included in
|
||||||
|
the metadata.
|
||||||
|
To be able to reproduce the same bytecode with such a remapping on a different machine, you
|
||||||
|
would need to recreate parts of your local directory structure in the VFS and (if you rely on
|
||||||
|
Host Filesystem Loader) also in the host filesystem.
|
||||||
|
|
||||||
|
As a more complex example, suppose you rely on a module that uses an old version of dapp-bin that
|
||||||
|
you checked out to ``/project/dapp-bin_old``, then you can run:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc module1:github.com/ethereum/dapp-bin/=dapp-bin/ \
|
||||||
|
module2:github.com/ethereum/dapp-bin/=dapp-bin_old/ \
|
||||||
|
--base-path /project \
|
||||||
|
source.sol
|
||||||
|
|
||||||
|
This means that all imports in ``module2`` point to the old version but imports in ``module1``
|
||||||
|
point to the new version.
|
||||||
|
|
||||||
|
Here are the detailed rules governing the behaviour of remappings:
|
||||||
|
|
||||||
|
#. **Remappings only affect the translation between import paths and source unit names.**
|
||||||
|
|
||||||
|
Source unit names added to the VFS in any other way cannot be remapped.
|
||||||
|
For example the paths you specify on the command-line and the ones in ``sources.urls`` in
|
||||||
|
Standard JSON are not affected.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc /project/=/contracts/ /project/contract.sol # source unit name: /project/contract.sol
|
||||||
|
|
||||||
|
In the example above the compiler will load the source code from ``/project/contract.sol`` and
|
||||||
|
place it under that exact source unit name in the VFS, not under ``/contract/contract.sol``.
|
||||||
|
|
||||||
|
#. **Context and prefix must match source unit names, not import paths.**
|
||||||
|
|
||||||
|
- This means that you cannot remap ``./`` or ``../`` directly since they are replaced during
|
||||||
|
the translation to source unit name but you can remap the part of the name they are replaced
|
||||||
|
with:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc ./=a/ /project/=b/ /project/contract.sol # source unit name: /project/contract.sol
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: /project/contract.sol
|
||||||
|
|
||||||
|
import "./util.sol" as util; // source unit name: b/util.sol
|
||||||
|
|
||||||
|
- You cannot remap base path or any other part of the path that is only added internally by an
|
||||||
|
import callback:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc /project/=/contracts/ /project/contract.sol --base-path /project # source unit name: /project/contract.sol
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: /project/contract.sol
|
||||||
|
|
||||||
|
import "util.sol" as util; // source unit name: util.sol
|
||||||
|
|
||||||
|
#. **Target is inserted directly into the source unit name and does not necessarily have to be a valid path.**
|
||||||
|
|
||||||
|
- It can be anything as long as the import callback can handle it.
|
||||||
|
In case of the Host Filesystem Loader this includes also relative paths.
|
||||||
|
When using the JavaScript interface you can even use URLs and abstract identifiers if
|
||||||
|
your callback can handle them.
|
||||||
|
|
||||||
|
- Remapping happens after relative imports have already been resolved into source unit names.
|
||||||
|
This means that targets starting with ``./`` and ``../`` have no special meaning and are
|
||||||
|
relative to the base path rather than to the location of the source file.
|
||||||
|
|
||||||
|
- Remapping targets are not normalized so ``@root/=./a/b//`` will remap ``@root/contract.sol``
|
||||||
|
to ``./a/b//contract.sol`` and not ``a/b/contract.sol``.
|
||||||
|
|
||||||
|
- If the target does not end with a slash, the compiler will not add one automatically:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc /project/=/contracts /project/contract.sol # source unit name: /project/contract.sol
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:caption: /project/contract.sol
|
||||||
|
|
||||||
|
import "/project/util.sol" as util; // source unit name: /contractsutil.sol
|
||||||
|
|
||||||
|
#. **Context and prefix are patterns and matches must be exact.**
|
||||||
|
|
||||||
|
- ``a//b=c`` will not match ``a/b``.
|
||||||
|
- source unit names are not normalized so ``a/b=c`` will not match ``a//b`` either.
|
||||||
|
- Parts of file and directory names can match as well.
|
||||||
|
``/newProject/con:/new=old`` will match ``/newProject/contract.sol`` and remap it to
|
||||||
|
``oldProject/contract.sol``.
|
||||||
|
|
||||||
|
#. **At most one remapping is applied to a single import.**
|
||||||
|
|
||||||
|
- If multiple remappings match the same source unit name, the one with the longest matching
|
||||||
|
prefix is chosen.
|
||||||
|
- If prefixes are identical, the one specified last wins.
|
||||||
|
- Remappings do not work on other remappings. For example ``a=b b=c c=d`` will not result in ``a``
|
||||||
|
being remapped to ``d``.
|
||||||
|
|
||||||
|
#. **Prefix cannot be empty but context and target are optional.**
|
||||||
|
|
||||||
|
If ``target`` is omitted, it defaults to the value of the ``prefix``.
|
||||||
|
|
||||||
|
.. index:: Remix IDE, file://
|
||||||
|
|
||||||
|
Using URLs in imports
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Most URL prefixes such as ``https://`` or ``data://`` have no special meaning in import paths.
|
||||||
|
The only exception is ``file://`` which is stripped from source unit names by the Host Filesystem
|
||||||
|
Loader.
|
||||||
|
|
||||||
|
When compiling locally you can use import remapping to replace the protocol and domain part with a
|
||||||
|
local path:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
solc :https://github.com/ethereum/dapp-bin=/usr/local/dapp-bin contract.sol
|
||||||
|
|
||||||
|
Note the leading ``:``, which is necessary when the remapping context is empty.
|
||||||
|
Otherwise the ``https:`` part would be interpreted by the compiler as the context.
|
@ -2,7 +2,7 @@
|
|||||||
Using the Compiler
|
Using the Compiler
|
||||||
******************
|
******************
|
||||||
|
|
||||||
.. index:: ! commandline compiler, compiler;commandline, ! solc, ! linker
|
.. index:: ! commandline compiler, compiler;commandline, ! solc
|
||||||
|
|
||||||
.. _commandline-compiler:
|
.. _commandline-compiler:
|
||||||
|
|
||||||
@ -33,11 +33,13 @@ This parameter has effects on the following (this might change in the future):
|
|||||||
- the size of the binary search in the function dispatch routine
|
- the size of the binary search in the function dispatch routine
|
||||||
- the way constants like large numbers or strings are stored
|
- the way constants like large numbers or strings are stored
|
||||||
|
|
||||||
Path Remapping
|
.. index:: allowed paths, --allow-paths, base path, --base-path
|
||||||
--------------
|
|
||||||
|
Base Path and Import Remapping
|
||||||
|
------------------------------
|
||||||
|
|
||||||
The commandline compiler will automatically read imported files from the filesystem, but
|
The commandline compiler will automatically read imported files from the filesystem, but
|
||||||
it is also possible to provide path redirects using ``prefix=path`` in the following way:
|
it is also possible to provide :ref:`path redirects <import-remapping>` using ``prefix=path`` in the following way:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -49,19 +51,24 @@ This essentially instructs the compiler to search for anything starting with
|
|||||||
the remapping targets and outside of the directories where explicitly specified source
|
the remapping targets and outside of the directories where explicitly specified source
|
||||||
files reside, so things like ``import "/etc/passwd";`` only work if you add ``/=/`` as a remapping.
|
files reside, so things like ``import "/etc/passwd";`` only work if you add ``/=/`` as a remapping.
|
||||||
|
|
||||||
An empty remapping prefix is not allowed.
|
When accessing the filesystem to search for imports, :ref:`paths that do not start with ./
|
||||||
|
or ../ <relative-imports>` are treated as relative to the directory specified using
|
||||||
If there are multiple matches due to remappings, the one with the longest common prefix is selected.
|
``--base-path`` option (or the current working directory if base path is not specified).
|
||||||
|
Furthermore, the part added via ``--base-path`` will not appear in the contract metadata.
|
||||||
When accessing the filesystem to search for imports, all paths are treated as if they were fully qualified paths.
|
|
||||||
This behaviour can be customized by adding the command line option ``--base-path`` with a path to be prepended
|
|
||||||
before each filesystem access for imports is performed. Furthermore, the part added via ``--base-path``
|
|
||||||
will not appear in the contract metadata.
|
|
||||||
|
|
||||||
For security reasons the compiler has restrictions what directories it can access. Paths (and their subdirectories) of source files specified on the commandline and paths defined by remappings are allowed for import statements, but everything else is rejected. Additional paths (and their subdirectories) can be allowed via the ``--allow-paths /sample/path,/another/sample/path`` switch.
|
|
||||||
|
|
||||||
|
For security reasons the compiler has restrictions on what directories it can access.
|
||||||
|
Directories of source files specified on the command line and target paths of
|
||||||
|
remappings are automatically allowed to be accessed by the file reader, but everything
|
||||||
|
else is rejected by default.
|
||||||
|
Additional paths (and their subdirectories) can be allowed via the
|
||||||
|
``--allow-paths /sample/path,/another/sample/path`` switch.
|
||||||
Everything inside the path specified via ``--base-path`` is always allowed.
|
Everything inside the path specified via ``--base-path`` is always allowed.
|
||||||
|
|
||||||
|
The above is only a simplification of how the compiler handles import paths.
|
||||||
|
For a detailed explanation with examples and discussion of corner cases please refer to the section on
|
||||||
|
:ref:`path resolution <path-resolution>`.
|
||||||
|
|
||||||
|
.. index:: ! linker, ! --link, ! --libraries
|
||||||
.. _library-linking:
|
.. _library-linking:
|
||||||
|
|
||||||
Library Linking
|
Library Linking
|
||||||
@ -79,6 +86,8 @@ Either add ``--libraries "file.sol:Math=0x12345678901234567890123456789012345678
|
|||||||
.. note::
|
.. note::
|
||||||
Starting Solidity 0.8.1 accepts ``=`` as separator between library and address, and ``:`` as a separator is deprecated. It will be removed in the future. Currently ``--libraries "file.sol:Math:0x1234567890123456789012345678901234567890 file.sol:Heap:0xabCD567890123456789012345678901234567890"`` will work too.
|
Starting Solidity 0.8.1 accepts ``=`` as separator between library and address, and ``:`` as a separator is deprecated. It will be removed in the future. Currently ``--libraries "file.sol:Math:0x1234567890123456789012345678901234567890 file.sol:Heap:0xabCD567890123456789012345678901234567890"`` will work too.
|
||||||
|
|
||||||
|
.. index:: --standard-json, --base-path
|
||||||
|
|
||||||
If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses. The process will always terminate in a "success" state and report any errors via the JSON output.
|
If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses. The process will always terminate in a "success" state and report any errors via the JSON output.
|
||||||
The option ``--base-path`` is also processed in standard-json mode.
|
The option ``--base-path`` is also processed in standard-json mode.
|
||||||
|
|
||||||
@ -166,6 +175,7 @@ at each version. Backward compatibility is not guaranteed between each version.
|
|||||||
the optimizer.
|
the optimizer.
|
||||||
|
|
||||||
|
|
||||||
|
.. index:: ! standard JSON, ! --standard-json
|
||||||
.. _compiler-api:
|
.. _compiler-api:
|
||||||
|
|
||||||
Compiler Input and Output JSON Description
|
Compiler Input and Output JSON Description
|
||||||
|
Loading…
Reference in New Issue
Block a user