Files
geef/mix.exs
Carlos Martín Nieto 9e9aa23af7 Fix some warnings from mix
2016-11-14 17:09:35 +01:00

144 lines
3.4 KiB
Elixir

defmodule Mix.Tasks.Compile.Nif do
@moduledoc """
A task to compile C code into a NIF.
To use, define a function in your project called `nif`.
## Configuration
* `:paths` - directories to find source files. Defaults to
`["c_src"]`. Can be configured as:
````
[paths: ["c_src", "vendor/src"]]
````
* `:exts` - extensions of the source files. Defaults to `[:c]`, can
be configured as:
```
[exts: [:c, :cpp]]
```
* `:file` - path of the shared object to compile to. Can be configured as:
````
[file: "priv/fancy.so"]
````
* `:flags` - flags to pass to the compiler. Can be configured as:
````
[flags: ["-lfancy", "-DDEBUG"]]
````
"""
def run(_) do
project = Mix.Project.get!
Mix.shell.info("* Running make...")
Mix.shell.info(:os.cmd('make'))
if function_exported?(project, :nif, 0) do
do_run(project.nif)
else
:noop
end
end
def do_run(config) do
file = Keyword.fetch!(config, :file)
paths = Keyword.get(config, :paths, ["c_src"])
flags = Keyword.get(config, :flags, [])
exts = Keyword.get(config, :exts, [:c])
compiler = Keyword.get(config, :compilers, ["cc", "gcc", "clang"]) |> find_compiler
flags =
case cflags = System.get_env("CFLAGS") do
# FIXME: this isn't going to work too well with quoted spaces
# inside arguments
true -> [flags, String.split(cflags)]
_ -> flags
end
# Create the directory (e.g. "priv/")
File.mkdir_p!(Path.dirname(file))
# Figure out whether we should compile the NIF. Compare the source
# files and header timestamps with the target binary. If the
# target is older than any source file, recompile.
to_compile = Mix.Utils.extract_files(paths, exts)
to_check = Mix.Utils.extract_files(paths, [:h | exts])
case Mix.Utils.extract_stale(to_check, [file]) do
[] ->
:noop
_ ->
Mix.shell.info("* Compiling #{file}")
args = ["-shared", "-fpic", "-o", file, to_compile, flags] |> List.flatten
port = Port.open({:spawn_executable, compiler},
[:stream, :binary, :use_stdio, :stderr_to_stdout, :hide,
:exit_status, {:args, args}])
if do_cmd(port) != 0 do
raise Mix.Error, message: "Error compiling #{file}"
end
:ok
end
end
defp find_compiler([compiler | tail]) do
case System.find_executable(compiler) do
nil ->
find_compiler(tail)
path ->
path
end
end
defp do_cmd(port) do
receive do
{^port, {:data, data}} ->
IO.write(data)
do_cmd(port)
{^port, {:exit_status, status}} ->
status
end
end
end
defmodule Geef.Mixfile do
use Mix.Project
def project do
[ app: :geef,
version: "0.0.1",
compilers: [:nif, :erlang, :elixir, :app],
deps: deps,
dialyzer: dialyzer ]
end
def nif do
[ file: "#{Path.join [__DIR__, "priv", "geef.so"]}",
flags: "-lgit2" ]
end
# Configuration for the OTP application
def application do
[]
end
# Returns the list of dependencies in the format:
# { :foobar, "0.1", git: "https://github.com/elixir-lang/foobar.git" }
defp deps do
[]
end
def dialyzer do
[ plt_apps: [:erts, :kernel, :stdlib, :mnesia],
flags: ["-Wunmatched_returns","-Werror_handling","-Wrace_conditions", "-Wno_opaque"]]
end
end