defmodule Zig.Options do @moduledoc """ parses and normalizes zig options. Also sets up `options.zig` file which is mapped to `@import("zigler_options")` in `beam.zig`. This is then exposed as `@import("beam").options` in your code. """ alias Zig.EasyC alias Zig.Module alias Zig.Nif @spec normalize!(keyword) :: keyword def normalize!(opts) do opts |> normalize_nifs_option! |> normalize_libs |> normalize_build_opts |> normalize_include_dirs |> normalize_c_src |> EasyC.normalize_aliasing() end @common_options ~w[leak_check]a @default_options Nif.default_options() defp normalize_nifs_option!(opts) do easy_c = Keyword.get(opts, :easy_c) if easy_c && !Keyword.has_key?(opts, :nifs) do raise CompileError, description: "nif specifications are required for easy_c nifs" end common = Keyword.merge(@default_options, Keyword.take(opts, @common_options)) opts |> Keyword.update(:nifs, {:auto, []}, &Module.normalize_nifs_option!(&1, common, easy_c)) |> Keyword.put(:default_options, common) end defp normalize_libs(opts) do Keyword.put(opts, :link_lib, List.wrap(opts[:link_lib])) end @use_gpa {:bool, "use_gpa", true} defp normalize_build_opts(opts) do # creates build_opts out of a list of build opt shortcuts use_gpa = Keyword.get(opts, :use_gpa, false) if use_gpa do Keyword.update(opts, :build_opts, [@use_gpa], fn list -> [@use_gpa | list] end) else opts end end defp normalize_include_dirs(opts) do Keyword.update(opts, :include_dir, [], fn path_or_paths -> path_or_paths |> List.wrap() |> Enum.map(&absolute_path_for(&1, opts)) end) end defp absolute_path_for("/" <> _ = path, _opts), do: path defp absolute_path_for(relative_path, opts) do opts |> Keyword.fetch!(:mod_file) |> Path.dirname() |> Path.join(relative_path) end # converts optional c_src option to a list of # {path, []} defp normalize_c_src(opts) do Keyword.update(opts, :c_src, [], fn path_or_paths -> path_or_paths |> List.wrap() |> Enum.flat_map(&normalize_c_src_paths(&1, opts)) end) end defp normalize_c_src_paths({path, c_opts}, opts) do unless is_list(c_opts), do: raise("c options for c source files must be a list") path |> absolute_path_for(opts) |> expand_directories |> Enum.map(fn file -> {file, c_opts} end) end defp normalize_c_src_paths(path, opts) when is_binary(path) do path |> absolute_path_for(opts) |> expand_directories |> Enum.map(fn file -> {file, []} end) end defp expand_directories(path) do List.wrap( if String.ends_with?(path, "/*") do path = String.replace_suffix(path, "/*", "") path |> File.ls!() |> Enum.flat_map(fn file -> List.wrap( if String.ends_with?(file, ".c") or String.ends_with?(file, ".cpp") do Path.join(path, file) end ) end) else path end ) end end