> ## Documentation Index
> Fetch the complete documentation index at: https://aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Link against pre-installed system libraries

> Link C programs in Bazel against system libraries like libmagic installed via apt or brew, a non-hermetic approach useful during migrations.

In the previous example we wrote a simple C program that only prints “hello world” and includes a standard header file. Real programs often use external code/libraries installed via system package manager (`apt` or `brew`) and link against it. It’s possible to use Bazel to do the same thing - rather than a “hermetic” build. This isn’t typically what you want, but might be useful during a migration, or for certain fixed development environments.

In this example we will write a simple program that reads a file and tries to determine what kind of file it is by using `libmagic`.  Before we do that, we need to install `libmagic` on our computers.

<Note>
  * MacOS users can `brew install libmagic` followed by `brew link libmagic`
  * Debian users can `apt-get install libmagic-dev`
  * Windows users can follow along by using Windows Subsystem for Linux (WSL).
</Note>

Here is an example C program that opens a file and tells the mime type using `libmagic`. Let’s name this `src/magic.c`.

```c theme={null}
#include <stdio.h>
#include <stdlib.h>
#include <magic.h>

int main(int argc, char *argv[]) {
    // Check if filename is provided
    if (argc != (int)2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    // Initialize magic handle
    magic_t magic = magic_open(MAGIC_MIME_TYPE);
    if (magic == NULL) {
        fprintf(stderr, "Failed to initialize libmagic\n");
        return 1;
    }

    // Load magic database
    if (magic_load(magic, NULL) != 0) {
        fprintf(stderr, "Cannot load magic database: %s\n", magic_error(magic));
        magic_close(magic);
        return 1;
    }

    // Get MIME type
    const char *mime_type = magic_file(magic, argv[1]);
    if (mime_type == NULL) {
        fprintf(stderr, "Error determining MIME type: %s\n", magic_error(magic));
        magic_close(magic);
        return 1;
    }

    // Print result
    printf("MIME type: %s\n", mime_type);

    // Cleanup
    magic_close(magic);
    return 0;
}
```

Outside of Bazel, compiling this program can be accomplished by running `gcc main.c -lmagic -o main` where the compiler is told to link against `libmagic` via `-lmagic`.

Here’s an equivalent Makefile, though note the portability issues with finding the `lib` and `include` folders:

```makefile theme={null}
main:
	gcc main.c -lmagic -o main \
	-L $(shell brew --prefix)/lib -I $(shell brew --prefix)/include
```

<Note>
  ❔

  On macOS  `-L $(brew --prefix)/lib -I $(brew --prefix)/include` flags have to be added to the command line to allow the compiler to find brew managed libraries. On Linux this is not necessary as `apt` installs everything under system `/usr`
</Note>

When compiling on macOS some additional configuration is also needed to allow linking against homebrew managed libraries.

```c theme={null}
llvm.toolchain(
    # Add /opt/homebrew to allowlist of linking against system libraries.
    cxx_builtin_include_directories = {
        "darwin-aarch64": ["/opt/homebrew"]
    },
)
```

Finally we can create a `cc_binary` target for our program and run it via `bazel run src:magic` and should see the `Usage:` line from earlier.

```python theme={null}
cc_binary(
    name = "magic",
    srcs = ["magic.cc"],
    copts = [
        # on macOS search for headers on homebrew managed /include directory.
        "-I/opt/homebrew/include",
    ],
    linkopts = [
        # link the magic library.
        "-lmagic",
        # on macOS allow linking against homebrew installed dylibs.
        "-L/opt/homebrew/lib",
       
    ]
)
```
