Skip to content

Instantly share code, notes, and snippets.

@andlabs
Created May 31, 2016 23:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andlabs/243d5d817d291fa62722c33a9c58c6ab to your computer and use it in GitHub Desktop.
Save andlabs/243d5d817d291fa62722c33a9c58c6ab to your computer and use it in GitHub Desktop.
libui Build System Requirements

libui Build System Requirements

Source Tree Layout

The libui source tree has a simple layout:

common/
    common sources and headers, .c and .h
darwin/
    darwin-specific sources and headers, .m and .h
examples/
    controlgallery/
        main.c
    cpp-multithread/
        main.cpp
    histogram/
        main.cpp
    a .rc and .manifest for Windows
test/
    test sources and headers, .c, .h, .rc, and .manifest 
unix/
    unix-specific sources and headers, .c and .h
windows/
    windows-specific sources and headers, .cpp, .hpp, .rc, and .manifest
ui.h
ui_darwin.h (the public Darwin-specific API)
ui_unix.h
ui_windows.h

Targets

There are 2*(3+n) targets (where n is the number of examples). The 2* comes because for each target, there is both a shared and a static mode, that affect linking. The 3 fixed targets are libui, the test program, and the special target examples that builds all the examples in one fell swoop. In addition, each example can be built individually.

A build of libui itself combines four items:

  • ui.h
  • ui_system.h
  • common/
  • system/

A build of the test program combines

  • ui.h
  • test/

A build of an example combines

  • ui.h
  • the specific main.c or main.cpp for that example

The Ideal Build Command

Ideally, a build program would be invoked as so:

$ build                          # builds only libui
$ build test                     # builds libui and test
$ build example EXAMPLE=name     # builds libui and given example
$ build examples                 # builds libui and all examples

In addition, the following additional arguments may be provided:

STATIC=1
    use static linking instead of shared linking
RELEASE=1
    make a release instead of a debug
VERBOSE=1
    show build steps (default is to show human-friendly progress)

So

build examples STATIC=1

builds libui as a static library and links all the examples statically to that static library.

Additionally, the standard CC, CXX, CFLAGS, CXXFLAGS, LD, LDFLAGS, RC, and RCFLAGS variables can be used to adjust build parameters.

By default, we build for the host OS. THis can be overridden with the OS variable. The OS name maps to the system folders above, so either darwin, unix (any other Unix system), or windows.

If the OS is Windows, the default toolchain is MSVC. To use a gcc/clang-based toolchain like MinGW-w64 instead, set the TOOLCHAIN variable, and (at present, due to internal limitations) static linking must be used (explicitly). The exact value isn't important. If the OS is not windows, only a gcc/clang-based toolchain will be available.

The actual build system does not need to use this exact syntax. This is just an explanation of how libui will be built through examples.

Build Flags

  • -Wall -Wextra -pedantic (and MSVC equivalent)
  • -Wno-unused-parameter -Wno-switch (and MSVC equivalent)
  • -fPIC (for non-Windows shared builds only)

libui itself also has

  • -fvisibility=hidden (for non-Windows builds only; this is important, see below)
  • -D_UI_EXTERN=something
  • -mmacosx-version-min=10.8 (on OS X)
  • MSVC safety options, maybe
  • Ideally for MSVC, .c files are built /TC

And finally, system libraries are linked only in:

  • libui shared build
  • test and example static build

On Static Libraries

Shared libraries are fine as they are.

Static libraries, on the other hand, need additional steps to ensure the -fvisibility=hidden setting required above actually works.

A normal static build would do

ar rcs library.a objects

However, this exposes hidden symbols to the caller, which will lead to name clashes which I don't want.

On non-OS X, if we instead do

ld -r objects -o hugeobject.o
objcopy --localize-hidden hugeobject.o
ar rcs library.a hugeobject.o

then we wind up with a library.a with the hidden symbols truly hidden, thanks to how ld -r and objcopy work: ld -r combines multiple .o files into one big .o file and objcopy rewrites that .o file to scramble the hidden symbols.

The equivalent on OS X is

nm -m objects | sed -E -n 's/^[0-9a-f]* \([A-Z_]+,[a-z_]+\) external //p' > symbols
ld -exported_symbols_list symbols -r objects -o hugeobject.o
ar rcs library.a hugeobject.o

A build system that allows me to specify custom rules for this will require me to also say that hugeobject.o should not be treated as a build product to be included along with libui and the executables.

Other General Wants

  • The ability to stuff all object files and per-source debugging symbol files in a separate directory such as .obj/
  • The ability to stuff all actual build output (libui and executables and final debugging symbols) in a separate directory such as out/
  • The ability to set rpath settings for both libui and executables
  • The ability to set a version number on libui's filename
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment