Replies: 6 comments 25 replies
It's worth noting that these issues arise before the compiler runs: One solution would be to move the responsibility for these over to the build tools (whether (This would of course be optional, plain
One thing I'd like to look into is adding an official project model, similar to Elixir. This lets them perform cross-module optimizations ("protocol consolidation"?) and various checks at compile time, which otherwise require separate runs of external tools like Having a similar model would let us share much of that work and opens the door to more aggressive optimizations (without necessarily sacrificing hot code upgrades 😎), but it's a lot more work than just fixing the above problems. I'd love to hear any ideas you have in this area. |
Do you mean static mapping like this: This may introduce mixing of layers - "application" and "project". As a developer I want to use some behaviour/transformation in my app, and ship it this way. It may be hard to re-use an application in multiple projects if However in order to properly support this, app.src would need to receive some concept of "profiles". For example, in "test" profile I want to add some parse_transform (from eunit, or pre-compile all files with cover). Same for dependencies, I do want to have "meck" in test, but not in production. |
More or less.
Not if the version is specified at the project ("release") level. An alternative would be for the build tool to figure out dependency versions once per build. I'm not going to tie myself down to any particular solution here but I'd like to see versions defined up front so that builds have a single known version of each (runtime) dependency, if that makes any sense.
We already mix layers: the version of each dependency is largely taken from the code path. I propose taking the version of each (runtime) dependency from a project/build definition instead, and it wouldn't prevent defining |
|
Hola! 👋🏽
I've been meaning to reply but haven't managed to until now 🙈. I saw
Maxim's answer and it touches the core issues I've had with the BEAM build
tooling thus far, so I'll try to explain.
Yes, build systems like Bazel, Buck, or Pants will not do file
scanning because that just does not scale. It does not scale in a single
machine, and it certainly does not scale for distributed builds.
Instead, these tools end up building the dependency graph lazily, from a
reverse-topological path (starting at the target), and deferring the
current target to a queue whenever they find an unmet dependency that needs
to be built first.
So instead of scanning, building a dependency tree, and then scoping the
path (A -> B -> C) when you ask for C, they just immediately begin at C and
ask: what does C need to be built? B. Okay lets build B instead and queue C
for later. Repeat until you find leaf targets that have no dependencies.
This also builds a queue in topo-sort that can be consumed by N-workers
parallelly. This gives you "O(1) builds" that scale linearly with respect
to the length of the path of the target being built.
Throw in a content-addressable cache for the targets and you get pretty
damn close to instant rebuilds at large scales. That's what you want. Sadly
these tools have a large upfront adoption cost since they force you as a
user to explicitly specify _every dependency_. Parse transforms, include
paths, env variables, everything should be explicitly annotated as a
dependency to a target.
Of course this is work done by a tool outside of the compiler, but it means
that the compiler should be able to be pointed to the right things
explicitly, and fail if they aren't there. Eg, include paths could be
"logical" (relative to the build system's view of the world) to support
things like remote build execution or distributed caches without a lot of
edge-casing. I've found myself vendoring and rewriting paths in libraries
to make them work with a prototype build system for the BEAM that follows
the philosophy mentioned above.
Again, sorry I couldn't get involved in the discussion earlier, and I hope
you find this input useful! 🙌🏽.
Side-note: I've been prototyping such a tool in the Zap project (
https://github.com/AbstractMachinesLab/zap) in the hopes of showcasing it
in our next meeting but I haven't been able to implement the last 20% that
actually gets us the "O(1) builds".
…On Mon, Mar 1, 2021 at 10:46 PM Maxim Fedorov ***@***.***> wrote:
Just looking at other build systems, they don't scan project root to find
all applications.
Instead, they start with some target. For example, a release (or target
system). That release has dependencies on several applications. Build tool
does not need to scan directories to find $app.app files, if paths are
known.
However requiring all applications to be in a single directory is not
desirable. We have short of 400 apps, structured in a dozen sub-folders
(some approximation of Java packages again).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#16 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGQRTTUDVHQEVRJAAS5GN3TBQDKVANCNFSM4XE7ZHTQ>
.
--
/ Leandro
|
|
I should add that in the OCaml ecosystem the dune (https://dune.build) tool
has done marvelous work at establishing new conventions and adopting
existing ones to make the benefits of tools like Bazel or Buck very very
cheap.
Adding the equivalent of a parse transform is a matter of dropping in a
line like: (preprocessors (pps ...)) in your library's dune file:
# this is the file path/to/lib/dune
(library
(name my_lib)
(libraries my_dep1 my_dep2)
(preprocessors (pps my_parse_transform)))
I've been building a rather large project with it (Caramel currently has
~5000 build targets, including vendored dependencies) and the experience
has been excellent.
But the OCaml compiler is rather dumb when it comes to looking for things!
So maybe keeping erlc dumber is better in the long haul.
…On Mon, Mar 1, 2021 at 11:16 PM Leandro Ostera ***@***.***> wrote:
Hola! 👋🏽
I've been meaning to reply but haven't managed to until now 🙈. I saw
Maxim's answer and it touches the core issues I've had with the BEAM build
tooling thus far, so I'll try to explain.
Yes, build systems like Bazel, Buck, or Pants will not do file
scanning because that just does not scale. It does not scale in a single
machine, and it certainly does not scale for distributed builds.
Instead, these tools end up building the dependency graph lazily, from a
reverse-topological path (starting at the target), and deferring the
current target to a queue whenever they find an unmet dependency that needs
to be built first.
So instead of scanning, building a dependency tree, and then scoping the
path (A -> B -> C) when you ask for C, they just immediately begin at C and
ask: what does C need to be built? B. Okay lets build B instead and queue C
for later. Repeat until you find leaf targets that have no dependencies.
This also builds a queue in topo-sort that can be consumed by N-workers
parallelly. This gives you "O(1) builds" that scale linearly with respect
to the length of the path of the target being built.
Throw in a content-addressable cache for the targets and you get pretty
damn close to instant rebuilds at large scales. That's what you want. Sadly
these tools have a large upfront adoption cost since they force you as a
user to explicitly specify _every dependency_. Parse transforms, include
paths, env variables, everything should be explicitly annotated as a
dependency to a target.
Of course this is work done by a tool outside of the compiler, but it
means that the compiler should be able to be pointed to the right things
explicitly, and fail if they aren't there. Eg, include paths could be
"logical" (relative to the build system's view of the world) to support
things like remote build execution or distributed caches without a lot of
edge-casing. I've found myself vendoring and rewriting paths in libraries
to make them work with a prototype build system for the BEAM that follows
the philosophy mentioned above.
Again, sorry I couldn't get involved in the discussion earlier, and I hope
you find this input useful! 🙌🏽.
Side-note: I've been prototyping such a tool in the Zap project (
https://github.com/AbstractMachinesLab/zap) in the hopes of showcasing it
in our next meeting but I haven't been able to implement the last 20% that
actually gets us the "O(1) builds".
On Mon, Mar 1, 2021 at 10:46 PM Maxim Fedorov ***@***.***>
wrote:
> Just looking at other build systems, they don't scan project root to find
> all applications.
> Instead, they start with some target. For example, a release (or target
> system). That release has dependencies on several applications. Build tool
> does not need to scan directories to find $app.app files, if paths are
> known.
>
> However requiring all applications to be in a single directory is not
> desirable. We have short of 400 apps, structured in a dozen sub-folders
> (some approximation of Java packages again).
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#16 (reply in thread)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAGQRTTUDVHQEVRJAAS5GN3TBQDKVANCNFSM4XE7ZHTQ>
> .
>
--
/ Leandro
--
/ Leandro
|
|
Even if we say that "all applications are folders in the project root and
their appname.src.in file lives in appname/src" we'd still need to scan the
project root to figure out what applications we have.
Calling `rebar3 build //apps/my_app` would know exactly where to start
building. You'd read the `app.src` file right at `./apps/my_app/app.src`
and let the dependency graph take you where you need to go.
If all paths are logical (absolute but in relation to the root of the
workspace), then you can just read the exact paths to the dependencies.
Both on local or remote builds.
This would mean you'd have to specify dependencies with a path instead. So
no `cowboy` but `//3rdparty/beam/cowboy`. And yes, this would mean that you
can have multiple applications with the same name.
…On Mon, Mar 1, 2021 at 11:22 PM Leandro Ostera ***@***.***> wrote:
I should add that in the OCaml ecosystem the dune (https://dune.build)
tool has done marvelous work at establishing new conventions and adopting
existing ones to make the benefits of tools like Bazel or Buck very very
cheap.
Adding the equivalent of a parse transform is a matter of dropping in a
line like: (preprocessors (pps ...)) in your library's dune file:
# this is the file path/to/lib/dune
(library
(name my_lib)
(libraries my_dep1 my_dep2)
(preprocessors (pps my_parse_transform)))
I've been building a rather large project with it (Caramel currently has
~5000 build targets, including vendored dependencies) and the experience
has been excellent.
But the OCaml compiler is rather dumb when it comes to looking for things!
So maybe keeping erlc dumber is better in the long haul.
On Mon, Mar 1, 2021 at 11:16 PM Leandro Ostera ***@***.***> wrote:
> Hola! 👋🏽
>
> I've been meaning to reply but haven't managed to until now 🙈. I saw
> Maxim's answer and it touches the core issues I've had with the BEAM build
> tooling thus far, so I'll try to explain.
>
> Yes, build systems like Bazel, Buck, or Pants will not do file
> scanning because that just does not scale. It does not scale in a single
> machine, and it certainly does not scale for distributed builds.
>
> Instead, these tools end up building the dependency graph lazily, from a
> reverse-topological path (starting at the target), and deferring the
> current target to a queue whenever they find an unmet dependency that needs
> to be built first.
>
> So instead of scanning, building a dependency tree, and then scoping the
> path (A -> B -> C) when you ask for C, they just immediately begin at C and
> ask: what does C need to be built? B. Okay lets build B instead and queue C
> for later. Repeat until you find leaf targets that have no dependencies.
> This also builds a queue in topo-sort that can be consumed by N-workers
> parallelly. This gives you "O(1) builds" that scale linearly with respect
> to the length of the path of the target being built.
>
> Throw in a content-addressable cache for the targets and you get pretty
> damn close to instant rebuilds at large scales. That's what you want. Sadly
> these tools have a large upfront adoption cost since they force you as a
> user to explicitly specify _every dependency_. Parse transforms, include
> paths, env variables, everything should be explicitly annotated as a
> dependency to a target.
>
> Of course this is work done by a tool outside of the compiler, but it
> means that the compiler should be able to be pointed to the right things
> explicitly, and fail if they aren't there. Eg, include paths could be
> "logical" (relative to the build system's view of the world) to support
> things like remote build execution or distributed caches without a lot of
> edge-casing. I've found myself vendoring and rewriting paths in libraries
> to make them work with a prototype build system for the BEAM that follows
> the philosophy mentioned above.
>
> Again, sorry I couldn't get involved in the discussion earlier, and I
> hope you find this input useful! 🙌🏽.
>
> Side-note: I've been prototyping such a tool in the Zap project (
> https://github.com/AbstractMachinesLab/zap) in the hopes of showcasing
> it in our next meeting but I haven't been able to implement the last 20%
> that actually gets us the "O(1) builds".
>
> On Mon, Mar 1, 2021 at 10:46 PM Maxim Fedorov ***@***.***>
> wrote:
>
>> Just looking at other build systems, they don't scan project root to
>> find all applications.
>> Instead, they start with some target. For example, a release (or target
>> system). That release has dependencies on several applications. Build tool
>> does not need to scan directories to find $app.app files, if paths are
>> known.
>>
>> However requiring all applications to be in a single directory is not
>> desirable. We have short of 400 apps, structured in a dozen sub-folders
>> (some approximation of Java packages again).
>>
>> —
>> You are receiving this because you were mentioned.
>> Reply to this email directly, view it on GitHub
>> <#16 (reply in thread)>,
>> or unsubscribe
>> <https://github.com/notifications/unsubscribe-auth/AAGQRTTUDVHQEVRJAAS5GN3TBQDKVANCNFSM4XE7ZHTQ>
>> .
>>
>
>
> --
> / Leandro
>
--
/ Leandro
--
/ Leandro
|
Uh oh!
There was an error while loading. Please reload this page.
Discussion brought in by @jhogberg:
Following the WG meeting, we felt that we should bring in the discussion about requirements and prior art across languages in this thread.
People of interest at first: @jhogberg, @josevalim @Ostera, @ferd, @tsloughter, anyone interested.
All reactions