thecodingidiot.com

The ToolkitSetup

Setup

No new tools needed for this chapter. Everything runs on the gcc, make, and valgrind you installed in f05/00.

Create a working directory

mkdir ~/c01-practice
cd ~/c01-practice

This is where all of libtci lives. One .c file per function, one shared header, one Makefile that builds the lot into a static library. You will spend the entire chapter here.

The initial structure

Create two files: the header and the Makefile. The header starts empty apart from its include guard. The Makefile starts with the right flags and grows as you add source files.

Create libtci.h:

#ifndef LIBTCI_H
#define LIBTCI_H
 
#include <stddef.h>
 
#endif

<stddef.h> is where size_t and NULL are declared. It is a minimal header — it does not pull in I/O or memory allocation; it only defines the types and constants that other headers depend on. Every function in libtci uses size_t for sizes and counts, so this include belongs at the top.

The #ifndef LIBTCI_H ... #endif block is an include guard. If another file includes libtci.h twice — directly or through a chain of other headers — the preprocessor only processes it once. Without the guard you get duplicate-declaration errors. Every header you write should have one. The convention is to name the guard after the filename in uppercase with the dot replaced by an underscore.

Create Makefile:

NAME    = libtci.a
CC      = gcc
CFLAGS  = -Wall -Wextra -g -std=c99
AR      = ar
ARFLAGS = rcs
 
SRCS    =
 
OBJS    = $(SRCS:.c=.o)
 
all: $(NAME)
 
$(NAME): $(OBJS)
	$(AR) $(ARFLAGS) $(NAME) $(OBJS)
 
%.o: %.c libtci.h
	$(CC) $(CFLAGS) -c $< -o $@
 
clean:
	rm -f $(OBJS)
 
fclean: clean
	rm -f $(NAME)
 
re: fclean all
 
.PHONY: all clean fclean re

The SRCS line is empty for now. You will add a filename each time you write a new .c file. The structure is the same Makefile you built in f05/06, with two differences.

First: the target is libtci.a, not an executable. There is no main. A library is a collection of compiled functions that other programs link against.

Second: the link step uses ar (the archive tool) instead of gcc. The rcs flags mean: replace or insert object files, create the archive if it does not exist, and write an index (symbol table) so the linker can find functions quickly. The result is a .a file — a static archive. Static is explained on the library page. For now, just know that running make will produce libtci.a from your .c files.

The %.o: %.c libtci.h rule means every .c file depends on libtci.h — a change to the header rebuilds everything.

Verify the Makefile works

Run make:

make

With SRCS empty there is nothing to build, so ar creates an empty archive:

ar rcs libtci.a

That is fine. The archive exists, it is empty, and make reports success. The structure is in place. Move on to the first page.

GNU libc and BSD functions

On Linux, the C standard library is GNU libc — glibc. It implements standard C (C99) and POSIX[1]. On macOS, the runtime is based on BSD libc, which adds functions that are not part of POSIX: strlcpy, strlcat, strnstr, and others.

This matters for libtci because several functions you will implement — tci_strlcpy, tci_strlcat, tci_strnstr — are not available in GNU libc on Linux. They will not be in <string.h> on your machine. libtci includes them because they are genuinely useful and absent on Linux: c01–c05 projects can use them without depending on a third-party library.

When a function has this origin it is noted in its section. Standard C and POSIX functions work identically on Linux and macOS. BSD-origin functions in libtci are libtci's own implementations, not wrappers around anything the system provides on Linux.

Footnotes

  1. POSIX - Wikipedia