Current section

Files

Jump to
exray lib Mix Tasks compile.exray.ex
Raw

lib/Mix/Tasks/compile.exray.ex

defmodule Mix.Tasks.Compile.Exray do
@moduledoc "Compile the Native Implemented Functions for Exray"
use Mix.Task
alias Unifex.InterfaceIO
alias Unifex.Specs
alias Unifex.CodeGenerator
alias Bundlex.Helper.MixHelper
alias Bundlex.Platform
alias Bundlex.Project
alias Bundlex.Output
alias Bundlex.Native
alias Bundlex.BuildScript
@shortdoc "Compile Unifex natives, Bundlex natives and Exray; generating Raylib bindings"
@impl Mix.Task
def run(_args) do
{:ok, exray_root} = Bundlex.Helper.MixHelper.get_project_dir(:exray)
{:ok, _apps} = Application.ensure_all_started(:exray)
{:ok, _apps} = Application.ensure_all_started(:unifex)
{:ok, _apps} = Application.ensure_all_started(:bundlex)
IO.puts(
"If Exray just spat out heaps of red errors about missing functions, the next lines are going to compile them; don't worry about it."
)
IO.puts("Compiling Unifex for Exray...")
compile_unifex(exray_root)
IO.puts("Compiling Bundlex for Exray...")
compile_bundlex()
:ok
end
# Shamelessly copy pasting the compile.unifex code because they discard `args`, which they should use to select path
defp compile_unifex(exray_root) do
exray_root
|> InterfaceIO.get_interfaces_specs!()
|> Enum.each(fn {name, dir, specs_file} ->
codes = specs_file |> Specs.parse(name) |> CodeGenerator.generate_code()
Enum.each(codes, &InterfaceIO.store_interface!(name, dir, &1))
generators = Enum.map(codes, fn {_header, _source, generator} -> generator end)
tie_header = CodeGenerator.TieHeader.generate_header(name, generators)
InterfaceIO.store_tie_header!(name, dir, tie_header)
InterfaceIO.store_gitignore!(dir)
end)
end
# Shamelessly copy pasting the compile.bundlex code because they discard `args`, which they should use to select app
defp compile_bundlex() do
commands = []
app = MixHelper.get_app!(:exray)
platform = Platform.get_target!()
project =
with({:ok, project} <- Project.get(:exray)) do
project
else
{:error, reason} ->
Bundlex.Output.raise(
"Cannot get project for app: #{inspect(app)}, reason: #{inspect(reason)}"
)
end
commands =
commands ++ Platform.get_module(platform).toolchain_module().before_all!(platform)
commands =
commands ++
case Native.resolve_natives(project, platform) do
{:ok, nifs_commands} ->
nifs_commands
{:error, {app, reason}} ->
Output.raise(
"Error resolving natives for app #{inspect(app)}, reason: #{inspect(reason)}"
)
end
build_script = BuildScript.new(commands)
{cmdline_options, _argv, _errors} =
OptionParser.parse(System.argv(), switches: [store_scripts: :boolean])
if cmdline_options[:store_scripts] do
{:ok, {filename, _script}} = build_script |> BuildScript.store(platform)
Output.info("Stored build script at #{File.cwd!() |> Path.join(filename)}")
end
case build_script |> BuildScript.run(platform) do
:ok ->
:ok
{:error, {:run_build_script, return_code: ret, command: cmd}} ->
Output.raise("""
Failed to build the native part of package #{app}. Errors may have been logged above.
Make sure that all required packages are properly installed in your system.
Requirements and installation guide may be found in the readme of package #{app}.
Returned code: #{ret}
Build script:
#{cmd}
""")
{:error, reason} ->
Output.raise("Error running build script, reason #{inspect(reason)}")
end
{:ok, []}
end
end