This is a minimal Objective C runtime written in C, designed to be portable across different platforms, including ARM and x86 architectures, mostly targeting embedded systems. It uses the "gcc" ABI for the moment, as that is the most portable across different platforms.
You will minimally need the following tools to build the runtime:
- Build system
make
andcmake
- for the build system - Compiler
clang
orgcc
- for compiling the runtime (clang
is not supported on Apple Silicon). You can use the environment variableCC
to specify the compiler, e.g.CC=clang
orCC=gcc
. - Library Dependencies
openssl
for Linux and Darwin - for the hash functions, which are used in the runtime and NXFoundation framework. - Documentation
docker
is needed for generating the documentation from the source code. - Cross-Compilation For cross-compilation for embedded systems based on some ARM variant, get the ARM LLVM toolchain: https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases. Install this to the
/opt
directory. You can use the environment variableTOOLCHAIN_PATH
to specify the path to the toolchain, e.g.TOOLCHAIN_PATH=/opt/LLVM-ET-Arm-19.1.5-Darwin-universal
.
Three static libraries are currently built:
objc-gcc
- the Objective C runtime library using the ancient GCC ABINXFoundation
- a minimal set of classes, to support memory management and basic types such as string, array, dictionary, date, time and number.runtime-sys
- a minimal set of system functions, needed to bind the runtime to the underlying system, on a per-platform basis. Includes cryptographic hash functions (MD5, SHA-256).
Download the source code from GitHub:
git clone git@github.com:djthorpe/objc.git
cd objc
The TOOLCHAIN_PATH
environment variable should point to the directory where the toolchain is installed.
For Macintosh, you can use Homebrew to install the GCC toolchain, which is required for compiling the runtime on MacOS:
# Compile with GCC 15 for MacOS
brew install gcc@15
TOOLCHAIN_PATH=/opt/homebrew RELEASE=1 CC=gcc-15 make
Once you've made the libraries, use the make tests
target to run the unit tests. There is information about test coverage in the tests directory.
You can target different architectures by setting the TARGET
environment variable. For a RP2040-based board, you can use the clang
compiler with the ARM toolchain. The TARGET
environment variable should be set to the target architecture, such as armv6m-none-eabi
for the RP2040 Pico board:
# Compile for the RP2040 Pico board
CC=clang TARGET=armv6m-none-eabi TOOLCHAIN_PATH=/opt/LLVM-ET-Arm-19.1.5-Darwin-universal RELEASE=1 make
See the list of supported targets in the cmake directory.
You can exclude the environment variable RELEASE=1
to build debugging versions of the libraries.
TODO: the libraries should be installed under a prefix path:
PREFIX=/opt/objc make install
- /opt/objc/lib/armv6m-none-eabi/libobjc-gcc.a
- /opt/objc/lib/armv6m-none-eabi/libruntime-sys.a
- /opt/objc/lib/armv6m-none-eabi/libFoundation.a
- /opt/objc/include/objc
- /opt/objc/include/sys
- /opt/objc/include/NXFoundation
- /opt/objc/doc/...
These can subsequently be used to make your executables!
To build the API documentation, you will need to have docker
installed. The documentation is built using doxygen
through docker
so you don't need to have it installed directly.
make docs
open docs/index.html
The documentation is also published here.
- Registering classes
- Simple message calling
-
NXConstantString
- Resolving super classes and meta classes for message lookup
- Calling methods in super classes - implement
[super init]
for example - Calling methods in categories
- Memory management - alloc, dealloc, memory arenas - require malloc in an
NXZone
- Printf support -
vsprintf
- printf-like function which can be used by NXLog, NXString and sys_panicf - Memory management - retain, release - reference counting for objects through NXZone
- Date and Time -
NXDate
- mutable date and time -
NXNumber
with booleans -
NXNull
- singleton for null objects that can be inserted into collections - Protocols and
conformsTo:
- Number -
NXNumber
withNXNumberInt16
andNXNumberUnsignedInt16
- Number -
NXNumber
withNXNumberInt32
andNXNumberUnsignedInt32
- Number -
NXNumber
withNXNumberInt64
andNXNumberUnsignedInt64
- Fix linking categories in static libraries (see test NXFoundation_05)
-
NXString
- mutable strings - append, appendFormat -
NXArray
- ordered collections of objects, with methods for adding, removing, and accessing objects -
NXData
- mutable binary data with Base64/hex encoding and append operations - Hash functions - MD5 and SHA-256 hash computation through
sys_hash_*
API - Pico toolchain - integrate with Pico SDK
- printf -
%@
format specifier for logging objects and[Object description]
- printf -
%T
format specifier for time intervals -
NXArray
- string methods - join - Robust sys_hash functions which hash some void* data against an arbitrary key, and a hashing function that can be used
-
NXMap
- unordered collections with string-keys (what aboutNXDictionary
?) -
NXMap
- arbitary key sizes -
@synchronized
support - use fixed-size table to store locks for objects, no allocations - clang compatibility
- Number -
NXNumberByte
andNXNumberInt8
-
respondsToSelector:
(see testruntime_14
) - Make all NX classes thread-safe, so that they can be used in multi-threaded applications
-
NXScanner
,ReaderProtocol
- scanning, parsing and tokenizing -
NXURL
class - URL/filepath parsing and manipulation - Classes have a unique number so we can do NXCoder to serialize and deserialize objects from binary data
-
NXData
- fix hexString encoding and decoding (see test NXFoundation_22) -
NXArray
sortWithFunction: sortedArrayWithFunction: reverse: and reversedArray: -
NXArray
filterWithFunction: filteredArrayWithFunction: - Pico - timer alarm pool should be on both cores, not just core 0, and then use the right pool for the core that the timer is running on
- Pico - when building RELEASE=1 builds it includes stdout and printf, which is not needed
-
NXRange
andNXString
- substringWithRange and substringWithRange:options: -
NXString
- rangeOfSubstring and rangeOfSubstring:options: -
NXArray
-subarrayWithRange:
andsubarrayWithRange:options:
-
NXString
- array methods - componentsSeparatedByString and componentsSeparatedByByte -
NXApplication
andNXRunLoop
- printf -
%f and %lf
format specifier for floats and doubles - Number -
NXNumber
withNXNumberFloat
andNXNumberDouble
- More efficient method implementation lookup
-
NXCoder
- JSON / Binary marshalling and unmarshalling -
make install
will compile the libraries and install them to a prefix path - Calling
+[initialise]
for categories - Exception handling?
Here are some references that may be useful for understanding the Objective C runtime and its implementation: