How to program with C API library on Windows using Bazel?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
On Windows, using a prebuilt C API library with Bazel usually means three separate integration tasks: expose the headers, link the import library, and make sure the DLL is available at runtime. In Bazel terms, the usual tool for this is cc_import, followed by a cc_binary or cc_library that depends on it. Once you model the prebuilt library correctly, the rest looks like ordinary C or C++ build wiring.
Know the Windows Library Pieces
A prebuilt Windows C API library often ships with:
- header files such as
mylib.h - an import library such as
mylib.lib - a runtime DLL such as
mylib.dll
The .lib file is what the linker usually consumes. The .dll is what your program needs at runtime.
That distinction matters because Bazel must be told about both.
Minimal cc_import Example
A typical Bazel setup looks like this:
This tells Bazel:
- which headers to expose to dependents
- which import library to link against
- which DLL is the runtime shared library
That is the core pattern for prebuilt shared libraries on Windows.
Example Consumer Code
Suppose mylib.h declares a simple C API function:
Then main.cc can use it normally:
The important part is that Bazel, not your IDE, owns the include and link setup.
Include Paths and Header Layout
If the vendor library has a nested include tree, preserve that structure in the workspace if possible. Bazel works best when the header path seen by the compiler matches the logical include path used by the code.
For example, if the library expects #include "vendor/mylib.h", mirror that structure rather than flattening everything into one directory.
That reduces confusion and makes the build rules easier to understand later.
Static Library Variant
If the vendor ships a static .lib rather than a DLL plus import library pair, the rule changes slightly. You would typically use the static_library attribute instead of interface_library and shared_library.
So before writing the Bazel rule, determine whether the .lib file is:
- an import library for a DLL
- a true static library
On Windows, the filename alone does not tell you which one it is.
Runtime DLL Availability
Linking successfully is not the end of the story. If the DLL is missing at runtime, the program can fail to start even though Bazel built it correctly.
That is why modeling the shared library properly in Bazel is important. The runtime artifact must be part of the runfiles or otherwise reachable by the executable.
Common Pitfalls
The biggest mistake is treating a Windows DLL as if Bazel only needs the .lib file. The DLL still matters at runtime.
Another mistake is confusing a static library with an import library because both may use the .lib extension.
A third issue is flattening the vendor header layout and then fighting include path problems that were created unnecessarily.
Summary
- On Windows, a prebuilt C API library usually involves headers, an import library, and a runtime DLL
- Use
cc_importto model the prebuilt library in Bazel - Link the import library and make sure the DLL is available at runtime
- Keep the vendor header layout consistent with the expected include paths
- Verify whether a
.libfile is static or just an import library before writing the Bazel rule

