Mac-side build

Building MacSurf on the Mac

Building MacSurf in CodeWarrior 8 Pro on Mac OS 9 — project settings, libraries, and the canonical compile loop.

Step-by-step guide to building MacSurf on a real Power Mac running Mac OS 9.


Dev Pack

The Dev Pack bundles everything on the MacSurf side of the build: the full source tree plus the MacSurf.mcp CodeWarrior project file, laid out so the relative access paths resolve as-is.

DevPackKit2.sit

Still needed (not included — supply your own): CarbonLib and CodeWarrior Pro 8.

Dev Pack current as of 7/15/26. Page last checked 7/30/26.


1. Installing CodeWarrior 8

Requirements: Power Mac G3 or G4, Mac OS 9.1 or later, 128MB RAM recommended, CD-ROM drive.

  1. Insert the CodeWarrior Pro 8 CD
  2. Double-click the installer — it will walk through license acceptance and destination selection
  3. Install to the default location (Macintosh HD:Metrowerks CodeWarrior:)
  4. When prompted for components, ensure these are checked:
    • MacOS PowerPC C/C++ Compiler
    • MacOS PowerPC Linker
    • MSL C Libraries (Metrowerks Standard Library)
    • Universal Headers (Mac OS Universal Interfaces)
  5. Skip the Java, Windows, and Palm OS tools — they are not needed
  6. After installation completes, open CodeWarrior IDE once to confirm it launches. It will create preferences in the System Folder
  7. Verify the Universal Headers are present at:
    Metrowerks CodeWarrior:MacOS Support:Headers:Universal Headers:
    
    You should see folders like CIncludes, PInterfaces, etc. If missing, run the installer again and check the Universal Headers checkbox

2. Opening the Project File

  1. Copy the entire macsurf/browser/netsurf/ directory tree to the Mac (see Section 6 for transfer method)
  2. Navigate to netsurf:frontends:macos9: in the Finder
  3. Double-click MacSurf.mcp — CodeWarrior will open it and display the project window
  4. If CodeWarrior prompts "Cannot find file..." for any source file, the directory structure was not preserved during transfer. Verify that the utils, content, and desktop folders exist three levels up from the macos9 folder
  5. The project window shows the source tree grouped by component. The build is large — roughly 470 .c files in total:
    • MacSurf frontend (~12 files) + POSIX shims (5 files)
    • NetSurf core — utils, content, desktop (~10 files)
    • libparserutils (15), libhubbub (30), libdom (95), libcss (303) — 443 files of ported NetSurf libraries, all C89-clean
    • macTLS (TLS 1.3) and the macQJS/QuickJS engine sources
    • MacSurf.rsrc — the pre-compiled resource fork carrying the mandatory 'carb' marker, the 'plst' bundle identity for OS X, the icon family, and the 'vers' resources. CW8 links .rsrc files straight into the output fork with no Rez step.

The CodeWarrior project mirrors the source directory tree through roughly 55 hierarchical access paths, not a single flat folder. The Dev Pack ships the authoritative project file and file list — don't hand-rebuild it.


3. Verifying Target Settings

  1. Go to Edit > MacSurf Settings... (or press Cmd-J)
  2. In the settings dialog, verify:

Target Settings panel:

C/C++ Language panel:

C/C++ Preprocessor panel:

The build uses a prefix file, macsurf_prefix.h, injected ahead of every translation unit. It defines:

#define TARGET_API_MAC_CARBON    1     /* MUST come before MacTypes.h — see below */
#define __MACOS9__               1
#define NO_IPV6                  1
#include <MacTypes.h>                  /* first include: prevents a bool/true/false clash */
...
#ifndef WITH_QUICKJS
#define WITH_QUICKJS             1     /* macQJS is in the base build */
#endif

Ordering gotcha that cost this project a great deal. TARGET_API_MAC_CARBON must be defined above the #include <MacTypes.h> line. MacTypes.h pulls in ConditionalMacros.h, which computes the Carbon triplet — OPAQUE_TOOLBOX_STRUCTS, OPAQUE_UPP_TYPES, ACCESSOR_CALLS_ARE_FUNCTIONS — at that moment and then guards itself against recomputation. Defining the flag later (for instance down in macos9.h) is too late and silently does nothing: all three come out 0 and you get a classic, non-Carbon binary compiled against Carbon headers. MacSurf shipped that way for its entire early history. CarbonLib on OS 9 tolerates it; Mac OS X does not, and it was the root cause behind every OS X crash until it was found.

WITHOUT_DUKTAPE no longer exists — Duktape was removed from the tree when macQJS (QuickJS) replaced it at the 1.68 release. JavaScript is gated by WITH_QUICKJS, which defaults on.

Access Paths panel:

PPC Processor panel:

  1. Click OK to save

4. First Build Attempt

Press Cmd-M (Project > Make) to start the build. Here is what to expect:

What will succeed

The POSIX shim files and frontend files should compile without errors — these have been syntax-checked on Linux with equivalent flags. Files that compiled clean in our Linux syntax-check rounds:

What will likely fail

Missing library headers. The project references headers from NetSurf dependency libraries (libwapcaplet, libcss, libdom, libparserutils, libhubbub). During Linux syntax checking, we copied these headers into netsurf/include/. Verify they are present on the Mac at:

netsurf:include:libwapcaplet:
netsurf:include:libcss:
netsurf:include:dom:
netsurf:include:parserutils:
netsurf:include:hubbub:
netsurf:include:nsutils:
netsurf:include:curl:

If any are missing, copy them from the corresponding browser/lib*/include/ directories.

CarbonLib linking. If the linker reports "CarbonLib not found", you need to add it manually:

  1. Go to Project > Add Files...
  2. Navigate to System Folder:Extensions:
  3. Select CarbonLib
  4. Add it to the Libraries group

MSL library path issues. CodeWarrior 8 ships MSL libraries in slightly different directory structures depending on the installer version. If "MSL C.Carbon.Lib" is not found:

  1. Use Sherlock (Cmd-F in Finder) to search for "MSL C.Carbon.Lib" on the boot volume
  2. Note the actual path
  3. In the project, remove the broken library reference and re-add from the correct location

Expected error count

On a clean build of an unmodified Dev Pack tree with the access paths intact: zero errors. All five NetSurf libraries are ported, C89-clean, and compiled as part of this project — there is no separate library build step and no expected crop of unresolved symbols. If you are seeing link errors for lwc_intern_string, css_stylesheet_create and friends, the library sources have dropped out of the project file or an access path is wrong, not "the libraries aren't built yet."

It is a big build. Expect it to take a while on vintage hardware, and don't be alarmed by warnings.


5. Reading CodeWarrior Error Output

The Errors & Warnings window

After a build, CodeWarrior shows an Errors & Warnings window. Each entry shows:

File "utils.c", line 477: warning: implicit declaration of 'strdup'

Common error patterns and what they mean

Error Message Likely Cause Fix
file not found: "libwapcaplet/libwapcaplet.h" Missing dependency library headers Copy headers into netsurf/include/ (see Section 4)
undefined identifier 'PATH_MAX' config.h __MACOS9__ block not active Verify __MACOS9__ is in the preprocessor prefix text (Section 3)
implicit declaration of 'strdup' POSIX function not declared Should be in utils/config.h under __MACOS9__ guard — check that the config.h edits from core-compile-attempt.md Round 2 are present
undefined identifier 'WindowRef' Mac Toolbox header not included Ensure #ifdef __MACOS9__ path includes <MacWindows.h> in the affected file
cannot convert 'void' to 'int' ns_close_socket macro issue Verify utils/inet.h has ((void)(s), 0) not ((void)(s)) for the __MACOS9__ case (fix from Round 3)
link failed: unresolved 'lwc_intern_string' libwapcaplet object code not in project Build libwapcaplet source or add its .c files to the project
link failed: unresolved 'css_stylesheet_create' libcss object code not in project Build libcss source or add its .c files to the project

Mapping errors to the task list

The project is structured in compilation layers matching the research docs:

  1. POSIX Shims — if these fail, fix the shim code first. Refer to posix-portability.md Section 2 for the implementation plan for each shim
  2. NetSurf Core Utils — errors here usually mean a config.h macro is wrong or a shim header is missing. Refer to core-compile-attempt.md for the exact fixes applied in each round
  3. NetSurf Content — depends on Utils compiling clean. Content-layer errors are usually missing library headers (libwapcaplet, libcss, libdom)
  4. NetSurf Desktop — depends on Content and Utils. Desktop errors are usually missing library headers or POSIX function declarations
  5. MacSurf Frontend — depends on all of the above. Frontend errors are usually missing Toolbox headers or Mac-specific API issues

Work bottom-up: fix shim errors first, then utils, then content, then desktop, then frontend.


6. Transferring Source Files from Linux to Mac

FAT32 thumb drive method

This is the easiest transfer method. Mac OS 9 reads FAT32 (called "DOS" in Mac OS 9) volumes via File Exchange.

On Linux:

  1. Format a USB thumb drive as FAT32 (most are already FAT32):

    # Only if reformatting is needed — this erases the drive
    sudo mkfs.vfat -F 32 /dev/sdX1
    
  2. Mount the drive and copy the source tree:

    mount /dev/sdX1 /mnt/usb
    cp -r browser/netsurf/ /mnt/usb/netsurf/
    sync
    umount /mnt/usb
    
  3. Line endings: Mac OS 9 expects CR (\r) line endings, not LF (\n). CodeWarrior 8 handles both, so this is usually not an issue for compilation. But if you edit files in SimpleText or BBEdit Lite on the Mac side, convert first:

    find /mnt/usb/netsurf -name "*.c" -o -name "*.h" | xargs sed -i 's/$/\r/'
    
  4. Filename length: FAT32 supports long filenames (up to 255 chars). All MacSurf filenames are well within this limit. No issues expected.

On the Mac:

  1. Insert the thumb drive. It should appear on the desktop as a DOS volume (generic disk icon)
  2. If it does not mount, open Control Panels > File Exchange and ensure "Mount DOS disks" is checked
  3. Open the drive and drag the netsurf folder to your hard drive — placing it wherever you want the project to live
  4. The Finder will copy all files, preserving the directory structure. FAT32 does not preserve Mac resource forks, but all MacSurf source files are plain text data-fork files, so nothing is lost

After transfer — verify structure

Open the netsurf folder on the Mac and confirm this structure exists:

netsurf:
  frontends:
    macos9:
      MacSurf.mcp        ← the project file
      main.c
      window.c
      ...
      shims:
        mac_iconv.c
        mac_file_io.c
        ...
  utils:
    utils.c
    config.h
    ...
  content:
    llcache.c
    fetch.c
    ...
  desktop:
    browser.c
    ...
  include:
    libwapcaplet:
    libcss:
    dom:
    ...

The MacSurf.mcp project file uses relative paths (../../../utils/utils.c etc.), so the directory hierarchy must be intact. If you placed files in a different structure, update the access paths in the project settings (Section 3).

Alternative: AppleTalk/FTP

If both machines are on the same network, Mac OS 9's built-in FTP Access (in the Internet control panel) or a third-party FTP client like Fetch can transfer files directly. But the thumb drive method avoids network configuration entirely and works with any Mac that has a USB port (all G3s and G4s do).

Discussion

Powered by GitHub Discussions — sign in with GitHub to comment.