# `Bundlex.Project`
[🔗](https://github.com/membraneframework/bundlex/blob/v1.5.8/lib/bundlex/project.ex#L1)

Behaviour that should be implemented by each project using Bundlex in the
`bundlex.exs` file.

# `config`

```elixir
@type config() :: [{:natives | :libs, [{native_name(), native_config()}]}]
```

Type describing input project configuration.

It's a keyword list, where natives and libs can be specified. Libs are
native packages that are compiled as static libraries and linked to natives
that have them specified in `deps` field of their configuration.

# `native_config`

```elixir
@type native_config() :: [
  sources: [String.t()],
  includes: [String.t()],
  lib_dirs: [String.t()],
  libs: [String.t()],
  os_deps: [os_dep()],
  pkg_configs: [String.t()],
  deps: [{Application.app(), native_name() | [native_name()]}],
  src_base: String.t(),
  compiler_flags: [String.t()],
  linker_flags: [String.t()],
  language: :c | :cpp,
  interface: native_interface() | [native_interface()],
  preprocessor:
    [Bundlex.Project.Preprocessor.t()] | Bundlex.Project.Preprocessor.t()
]
```

Type describing configuration of a native.

Configuration of each native may contain following options:
* `sources` - C files to be compiled (at least one must be provided).
* `preprocessors` - Modules that will pre-process the native. They may change this configuration, for example
by adding new keys. An example of preprocessor is [Unifex](https://hexdocs.pm/unifex/Unifex.html).
See `Bundlex.Project.Preprocessor` for more details.
* `interface` - Interface used to integrate with Elixir code. The following interfaces are available:
  * :nif - dynamically linked to the Erlang VM (see [Erlang docs](http://erlang.org/doc/man/erl_nif.html))
  * :cnode - executed as separate OS processes, accessed through sockets (see [Erlang docs](http://erlang.org/doc/man/ei_connect.html))
  * :port - executed as separate OS processes (see [Elixir Port docs](https://hexdocs.pm/elixir/Port.html))
Specifying no interface is valid only for libs.
* `deps` - Dependencies in the form of `{app, lib_name}`, where `app`
is the application name of the dependency, and `lib_name` is the name of lib
specified in Bundlex project of this dependency. Empty list by default. See _Dependencies_ section below
for details.
* `os_deps` - List of external OS dependencies. It's a keyword list, where each key is the
dependency name and the value is a provider or a list of them. In the latter case, subsequent
providers from the list will be tried until one of them succeeds. A provider may be one of:
  - `pkg_config` - Resolves the dependency via `pkg-config`. Can be either `{:pkg_config, pkg_configs}`
  or just `:pkg_config`, in which case the dependency name will be used as the pkg_config name.
  - `precompiled` - Downloads the dependency from a given url and sets appropriate compilation
  and linking flags. Can be either `{:precompiled, url, libs}` or `{:precompiled, url}`, in which
  case the dependency name will be used as the lib name.
  Precompiled dependencies can be disabled via configuration globally:

    ```elixir
    config :bundlex, :disable_precompiled_os_deps, true
    ```

    or for given applications (Mix projects), for example:

    ```elixir
    config :bundlex, :disable_precompiled_os_deps,
      apps: [:my_application, :another_application]
    ```

    Note that this will affect the natives and libs defined in the `bundlex.exs` files of specified
    applications only, not in their dependencies.

  Check `t:os_dep/0` for details.
* `pkg_configs` - (deprecated, use `os_deps` instead) Names of libraries for which the appropriate flags will be
obtained using pkg-config (empty list by default).
* `language` - Language of native. `:c` or `:cpp` may be chosen (`:c` by default).
* `src_base` - Native files should reside in `project_root/c_src/<src_base>`
(application name by default).
* `includes` - Paths to look for header files (empty list by default).
* `lib_dirs` - Absolute paths to look for libraries (empty list by default).
* `libs` - Names of libraries to link (empty list by default).
* `compiler_flags` - Custom flags for compiler. Default `-std` flag for `:c` is `-std=c11` and for `:cpp` is `-std=c++17`.
* `linker_flags` - Custom flags for linker.

# `native_interface`

```elixir
@type native_interface() :: :nif | :cnode | :port
```

# `native_language`

```elixir
@type native_language() :: :c | :cpp
```

# `native_name`

```elixir
@type native_name() :: atom()
```

# `os_dep`

```elixir
@type os_dep() :: {name :: atom(), os_dep_provider() | [os_dep_provider()]}
```

# `os_dep_provider`

```elixir
@type os_dep_provider() ::
  :pkg_config
  | {:pkg_config, pkg_configs :: String.t() | [String.t()]}
  | {:precompiled, url :: String.t()}
  | {:precompiled, url :: String.t(), libs :: String.t() | [String.t()]}
```

# `t`

```elixir
@type t() :: %Bundlex.Project{
  app: atom(),
  config: config(),
  module: module(),
  src_path: String.t()
}
```

Struct representing bundlex project.

Contains the following fields:
- `:config` - project configuration
- `:src_path` - path to the native sources
- `:module` - bundlex project module
- `:app` - application that exports project

# `project`

```elixir
@callback project() :: config()
```

Callback returning project configuration.

# `get`

```elixir
@spec get(application :: atom()) ::
  {:ok, t()}
  | {:error,
     :invalid_project_specification
     | {:no_bundlex_project_in_file, path :: binary()}
     | :unknown_application}
```

Returns the project struct of given application.

If the module has not been loaded yet, it is loaded from
`project_dir/bundlex.exs` file.

# `native_config_keys`

```elixir
@spec native_config_keys() :: [atom()]
```

# `project_module?`

```elixir
@spec project_module?(module()) :: boolean()
```

Determines if `module` is a bundlex project module.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
