This project demonstrates creating a macOS executable that can also be loaded as a dynamic library.
The binary is built as a Position Independent Executable (PIE) with exported symbols using C++:
-fPIC: Position Independent Code-Wl,-export_dynamic: Export symbols for dynamic loading-Wl,-pie: Create a PIE executable__attribute__((visibility("default"))): Mark functions for export- C++ std::chrono for timestamp initialization
makeThis creates binaries in the build/ directory:
build/dyexe- The dual-purpose binarybuild/test_loader- A test program that loads dyexe as a library
The executable prints a Unix timestamp (seconds since epoch) to stdout:
build/dyexe
# Output: 1766845603build/test_loader build/dyexeOr programmatically in C:
void *handle = dlopen("./dyexe", RTLD_LAZY);
long long (*get_time)(void) = dlsym(handle, "dyexe_get_time");
long long timestamp = get_time();
dlclose(handle);Run all tests:
make testThis runs:
- Executable test (
test_executable.sh): Spawns the executable, captures stdout, and verifies the timestamp is close to current time - Library test (
test_loader):- Loads dyexe as a dynamic library
- Calls
dyexe_get_time()twice and verifies both calls return the same value - Verifies the timestamp is close to current time
Run individual tests:
# Test executable mode
./test_executable.sh build/dyexe
# Test library mode
build/test_loader build/dyexelong long dyexe_get_time(void)- Returns Unix timestamp (seconds since epoch) initialized at program start
make clean