diff --git a/emulator/resources/Info.plist b/emulator/resources/Info.plist index 9afd51a71..17ab3507d 100644 --- a/emulator/resources/Info.plist +++ b/emulator/resources/Info.plist @@ -31,5 +31,30 @@ DISPLAY :0 + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + midi + mid + kar + + CFBundleTypeIconFile + SwadgeEmulator.icns + CFBundleTypeNames + MIDI File + CFBundleTypeOSTypes + + Midi + + LSItemContentTypes + + public.midi-audio + + CFBundleTypeRole + Viewer + + diff --git a/emulator/src/extensions/midi/ext_midi.c b/emulator/src/extensions/midi/ext_midi.c index ca39ac292..bb6e8a4e7 100644 --- a/emulator/src/extensions/midi/ext_midi.c +++ b/emulator/src/extensions/midi/ext_midi.c @@ -1,6 +1,7 @@ #include "ext_midi.h" #include "emu_ext.h" #include "emu_main.h" +#include "emu_utils.h" #include "hdw-nvs_emu.h" #include "emu_cnfs.h" @@ -8,12 +9,50 @@ #include "mode_synth.h" #include +#include +#include + +#ifdef EMU_MACOS + // Used to handle DocumentOpen event that OSX uses instead of Just Putting It In Argv + #include +#endif + +//============================================================================== +// Types +//============================================================================== + +#ifdef EMU_MACOS +typedef void (*MacOpenFileCb)(const char* path); + +typedef struct +{ + EventHandlerUPP globalEventHandler; + AEEventHandlerUPP appleEventHandler; + EventHandlerRef globalEventHandlerRef; + MacOpenFileCb openFileCallback; +} MacOpenFileHandler; +#endif //============================================================================== // Function Prototypes //============================================================================== static bool midiInitCb(emuArgs_t* emuArgs); +static void midiPreFrameCb(uint64_t frame); +static bool midiInjectFile(const char* path); + +#ifdef EMU_MACOS +// Exists but isn't declared in the headers +extern Boolean ConvertEventRefToEventRecord(EventRef, EventRecord*); + +bool installMacOpenFileHandler(MacOpenFileHandler* handlerRef, MacOpenFileCb callback); +void checkForEventsMacOpenFileHandler(MacOpenFileHandler* handlerRef, uint32_t millis); +void uninstallMacOpenFileHandler(MacOpenFileHandler* handlerRef); + +static pascal OSErr handleOpenDocumentEvent(const AppleEvent* event, AppleEvent* reply, SRefCon handlerRef); +static OSStatus globalEventHandler(EventHandlerCallRef handler, EventRef event, void* data); +static void doFileOpenCb(const char* path); +#endif //============================================================================== // Variables @@ -22,7 +61,7 @@ static bool midiInitCb(emuArgs_t* emuArgs); emuExtension_t midiEmuExtension = { .name = "midi", .fnInitCb = midiInitCb, - .fnPreFrameCb = NULL, + .fnPreFrameCb = midiPreFrameCb, .fnPostFrameCb = NULL, .fnKeyCb = NULL, .fnMouseMoveCb = NULL, @@ -30,6 +69,17 @@ emuExtension_t midiEmuExtension = { .fnRenderCb = NULL, }; +static char midiPathBuffer[1024]; +static const char* midiFile = NULL; + +#ifdef EMU_MACOS +static const EventTypeSpec eventTypes[] = {{.eventClass = kEventClassAppleEvent, .eventKind = kEventAppleEvent}}; + +static bool handlerInstalled = false; +static bool emulatorStarted = false; +static MacOpenFileHandler macOpenFileHandler; +#endif + //============================================================================== // Functions //============================================================================== @@ -38,14 +88,20 @@ static bool midiInitCb(emuArgs_t* emuArgs) { if (emuArgs->midiFile) { - printf("Opening MIDI file: %s\n", emuArgs->midiFile); - if (emuCnfsInjectFile(emuArgs->midiFile, emuArgs->midiFile)) - { - emuInjectNvs32("storage", "synth_playmode", 1); - emuInjectNvsBlob("storage", "synth_lastsong", strlen(emuArgs->midiFile), emuArgs->midiFile); - emulatorSetSwadgeModeByName(synthMode.modeName); - } - else + midiFile = emuArgs->midiFile; + } + +#ifdef EMU_MACOS + handlerInstalled = installMacOpenFileHandler(&macOpenFileHandler, doFileOpenCb); + // Wait up to 100ms for an event at startup + checkForEventsMacOpenFileHandler(&macOpenFileHandler, 100); + emulatorStarted = true; +#endif + + if (midiFile) + { + printf("Opening MIDI file: %s\n", midiFile); + if (!midiInjectFile(midiFile)) { printf("Could not read MIDI file!\n"); emulatorQuit(); @@ -56,4 +112,243 @@ static bool midiInitCb(emuArgs_t* emuArgs) } return false; -} \ No newline at end of file +} + +void midiPreFrameCb(uint64_t frame) +{ +#ifdef EMU_MACOS + if (handlerInstalled) + { + // Wait up to 5ms for an event, is that enough? + checkForEventsMacOpenFileHandler(&macOpenFileHandler, 5); + } +#endif +} + +static bool midiInjectFile(const char* path) +{ + if (emuCnfsInjectFile(midiFile, midiFile)) + { + emuInjectNvs32("storage", "synth_playmode", 1); + emuInjectNvsBlob("storage", "synth_lastsong", strlen(midiFile), midiFile); + emulatorSetSwadgeModeByName(synthMode.modeName); + + return true; + } + else + { + return false; + } +} + +#ifdef EMU_MACOS +static void doFileOpenCb(const char* path) +{ + strncpy(midiPathBuffer, path, sizeof(midiPathBuffer)); + midiFile = midiPathBuffer; + + if (emulatorStarted) + { + if (!midiInjectFile(path)) + { + printf("Error: could not read MIDI file %s!\n", path); + } + } +} + +bool installMacOpenFileHandler(MacOpenFileHandler* handlerRef, MacOpenFileCb callback) +{ + // Init handler + handlerRef->appleEventHandler = NULL; + handlerRef->globalEventHandler = NULL; + handlerRef->openFileCallback = callback; + + // Install handler + handlerRef->appleEventHandler = NewAEEventHandlerUPP(handleOpenDocumentEvent); + OSStatus result = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, handlerRef->appleEventHandler, + (SRefCon)handlerRef, false); + + if (result != noErr) + { + printf("Failed to install OpenDocument handler\n"); + uninstallMacOpenFileHandler(handlerRef); + return false; + } + + // Install the application-level handler + handlerRef->globalEventHandler = NewEventHandlerUPP(globalEventHandler); + result = InstallApplicationEventHandler(handlerRef->globalEventHandler, 1, eventTypes, NULL, + &handlerRef->globalEventHandlerRef); + + if (result != noErr) + { + printf("Failed to install global event handler\n"); + uninstallMacOpenFileHandler(handlerRef); + return false; + } + + // Handler successfully installed + return true; +} + +// Runs the event loop and waits for up to the specified time +// The callback will be called for any events that are recevied +void checkForEventsMacOpenFileHandler(MacOpenFileHandler* handlerRef, uint32_t millis) +{ + EventTimeout timeout = millis / 1000.0; + while (1) + { + EventRef eventRef; + + OSErr result = ReceiveNextEvent(1, eventTypes, timeout, kEventRemoveFromQueue, &eventRef); + + if (result == eventLoopTimedOutErr) + { + // printf("No event received after timeout\n"); + break; + } + else if (result == noErr) + { + result = SendEventToEventTarget(eventRef, GetEventDispatcherTarget()); + ReleaseEvent(eventRef); + if (result != noErr) + { + if (result == eventNotHandledErr) + { + // printf("Got eventNotHandledErr from SendEventToEventTarget()\n"); + } + else + { + printf("Error in SendEventToEventTarget(): %d %s\n", result, strerror(result)); + break; + } + } + } + else + { + printf("Error in ReceiveNextEvent()\n"); + break; + } + } +} + +// Uninstalls and deletes +void uninstallMacOpenFileHandler(MacOpenFileHandler* handlerRef) +{ + if (handlerRef != NULL) + { + if (handlerRef->appleEventHandler != NULL) + { + DisposeAEEventHandlerUPP(handlerRef->appleEventHandler); + handlerRef->appleEventHandler = NULL; + } + + if (handlerRef->globalEventHandler != NULL) + { + DisposeEventHandlerUPP(handlerRef->globalEventHandler); + handlerRef->globalEventHandler = NULL; + } + handlerRef->openFileCallback = NULL; + } +} + +static pascal OSErr handleOpenDocumentEvent(const AppleEvent* event, AppleEvent* reply, SRefCon handlerRefArg) +{ + MacOpenFileHandler* handlerRef = (MacOpenFileHandler*)handlerRefArg; + + AEDescList docList; + OSErr result = AEGetParamDesc(event, keyDirectObject, typeAEList, &docList); + + if (result != noErr) + { + return result; + } + + long docCount = 0; + result = AECountItems(&docList, &docCount); + if (result != noErr) + { + return result; + } + + char buffer[2048]; + + // Yup, it's zero-indexed. Weird. + for (long i = 1; i <= docCount; i++) + { + AEKeyword keyword; + DescType docType; + Size docSize; + + result = AEGetNthPtr(&docList, i, typeFileURL, &keyword, &docType, &buffer, sizeof(buffer), &docSize); + + if (result != noErr) + { + return result; + } + + CFURLRef docUrlRef = CFURLCreateWithBytes(NULL, (UInt8*)buffer, docSize, kCFStringEncodingUTF8, NULL); + + if (docUrlRef != NULL) + { + CFStringRef docStringRef = CFURLCopyFileSystemPath(docUrlRef, kCFURLPOSIXPathStyle); + if (docStringRef != NULL) + { + char pathBuffer[1024]; + if (CFStringGetFileSystemRepresentation(docStringRef, pathBuffer, sizeof(pathBuffer))) + { + handlerRef->openFileCallback(pathBuffer); + } + CFRelease(docStringRef); + } + CFRelease(docUrlRef); + } + } + + return AEDisposeDesc(&docList); +} + +static OSStatus globalEventHandler(EventHandlerCallRef handler, EventRef event, void* data) +{ + bool inQueue = IsEventInQueue(GetMainEventQueue(), event); + + if (inQueue) + { + RetainEvent(event); + RemoveEventFromQueue(GetMainEventQueue(), event); + } + + EventRecord record; + ConvertEventRefToEventRecord(event, &record); + char messageStr[5] = { + (char)((record.message >> 24) & 0xff), + (char)((record.message >> 16) & 0xff), + (char)((record.message >> 8) & 0xff), + (char)((record.message) & 0xff), + 0, + }; + printf("globalEventHandler() what=%hu, message=%s\n", record.what, messageStr); + OSStatus result = AEProcessAppleEvent(&record); + + if (result == errAEEventNotHandled) + { + printf("errAEEventNotHandled in globalEventHandler()\n"); + } + else if (result != noErr) + { + printf("globalEventHandler() AEProcessAppleEvent() returned ERROR: %d (%s)\n", result, strerror(result)); + } + else + { + printf("globalEventHandler() AEProcessAppleEvent() success!\n"); + } + + if (inQueue) + { + ReleaseEvent(event); + } + + return noErr; +} + +#endif diff --git a/makefile b/makefile index 60555451d..6f07470c8 100644 --- a/makefile +++ b/makefile @@ -279,6 +279,7 @@ LIBRARY_FLAGS += \ -static-libstdc++ else LIBRARY_FLAGS += \ + -framework Carbon \ -framework Foundation \ -framework CoreFoundation \ -framework CoreMIDI \ diff --git a/tools/mac_events_test/.gitignore b/tools/mac_events_test/.gitignore new file mode 100644 index 000000000..5e53c4401 --- /dev/null +++ b/tools/mac_events_test/.gitignore @@ -0,0 +1,4 @@ +test +test.icns +test.app + diff --git a/tools/mac_events_test/Info.plist b/tools/mac_events_test/Info.plist new file mode 100644 index 000000000..3484970e6 --- /dev/null +++ b/tools/mac_events_test/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + test + CFBundleGetInfoString + Public Domain + CFBundleIconFile + test.icns + CFBundleIdentifier + com.dylwhich.osxargtest + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + test + CFBundleVersion + 1.0 + NSHumanReadableCopyright + Public Domain + LSMinimumSystemVersion + 10 + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + midi + mid + kar + + CFBundleTypeIconFile + test.icns + CFBundleTypeNames + MIDI File + CFBundleTypeOSTypes + + Midi + + LSItemContentTypes + + public.midi-audio + + CFBundleTypeRole + Viewer + + + + diff --git a/tools/mac_events_test/main.c b/tools/mac_events_test/main.c new file mode 100644 index 000000000..4d886ef3f --- /dev/null +++ b/tools/mac_events_test/main.c @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include + +#include + +extern Boolean ConvertEventRefToEventRecord(EventRef, EventRecord*); + +#define LOG_FILE "/Users/dylwhich/events.log" + +#ifdef LOG_FILE +#define LOG(...) fprintf(logFile, __VA_ARGS__) +#else +#define LOG printf +#endif + +typedef void (*MacOpenFileCb)(const char* path); + +typedef struct +{ + EventHandlerUPP globalEventHandler; + AEEventHandlerUPP appleEventHandler; + MacOpenFileCb openFileCallback; + EventHandlerRef globalEventHandlerRef; +} MacOpenFileHandler; + +bool installMacOpenFileHandler(MacOpenFileHandler* handlerRef, MacOpenFileCb callback); +void checkForEventsMacOpenFileHandler(MacOpenFileHandler* handlerRef, uint32_t millis); +void uninstallMacOpenFileHandler(MacOpenFileHandler* handlerRef); + +static pascal OSErr handleOpenDocumentEvent(const AppleEvent* event, AppleEvent* reply, SRefCon handlerRef); +static OSStatus globalEventHandler(EventHandlerCallRef handler, EventRef event, void* data); +static void doOpenCb(const char* path); + +FILE* logFile; + +const EventTypeSpec eventTypes[] = {{.eventClass = kEventClassAppleEvent, .eventKind = kEventAppleEvent}}; + +static void doOpenCb(const char* path) +{ + LOG("Got file: %s\n", path); +} + +int main(int argc, char** argv) +{ +#ifdef LOG_FILE + logFile = fopen(LOG_FILE, "a"); +#endif + + LOG("\nStarting up\n"); + + LOG("Installing event handler...\n"); + MacOpenFileHandler handler; + + bool installed = installMacOpenFileHandler(&handler, doOpenCb); + + if (installed) + { + LOG("OK!\n"); + checkForEventsMacOpenFileHandler(&handler, 500); + uninstallMacOpenFileHandler(&handler); + LOG("Done processing events\n"); + } + else + { + LOG("FAILED!"); + return 1; + } + + return 0; +} + +bool installMacOpenFileHandler(MacOpenFileHandler* handlerRef, MacOpenFileCb callback) +{ + // Init handler + handlerRef->appleEventHandler = NULL; + handlerRef->globalEventHandler = NULL; + handlerRef->openFileCallback = callback; + + // Install handler + handlerRef->appleEventHandler = NewAEEventHandlerUPP(handleOpenDocumentEvent); + OSStatus result = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, handlerRef->appleEventHandler, (SRefCon)handlerRef, false); + + if (result != noErr) + { + LOG("Failed to install OpenDocument handler\n"); + uninstallMacOpenFileHandler(handlerRef); + return false; + } + + // Install the application-level handler + handlerRef->globalEventHandler = NewEventHandlerUPP(globalEventHandler); + result = InstallApplicationEventHandler(handlerRef->globalEventHandler, 1, eventTypes, NULL, &handlerRef->globalEventHandlerRef); + + if (result != noErr) + { + LOG("Failed to install global event handler\n"); + uninstallMacOpenFileHandler(handlerRef); + return false; + } + + // Handler successfully installed + return true; +} + +// Runs the event loop and waits for up to the specified time +// The callback will be called for any events that are recevied +void checkForEventsMacOpenFileHandler(MacOpenFileHandler* handlerRef, uint32_t millis) +{ + EventTimeout timeout = millis / 1000.0; + while (1) + { + EventRef eventRef; + + OSErr result = ReceiveNextEvent(1, eventTypes, timeout, kEventRemoveFromQueue, &eventRef); + + if (result == eventLoopTimedOutErr) + { + LOG("No event received after timeout\n"); + break; + } + else if (result == noErr) + { + LOG("Got an event!\n"); + result = SendEventToEventTarget(eventRef, GetEventDispatcherTarget()); + ReleaseEvent(eventRef); + if (result != noErr) + { + if (result == eventNotHandledErr) + { + LOG("Got eventNotHandledErr from SendEventToEventTarget()\n"); + } + else + { + LOG("Error in SendEventToEventTarget(): %d %s\n", result, strerror(result)); + break; + } + } + } + else + { + LOG("Error in ReceiveNextEvent()\n"); + break; + } + } +} + +// Uninstalls and deletes +void uninstallMacOpenFileHandler(MacOpenFileHandler* handlerRef) +{ + if (handlerRef != NULL) + { + if (handlerRef->appleEventHandler != NULL) + { + DisposeAEEventHandlerUPP(handlerRef->appleEventHandler); + handlerRef->appleEventHandler = NULL; + } + + if (handlerRef->globalEventHandler != NULL) + { + DisposeEventHandlerUPP(handlerRef->globalEventHandler); + handlerRef->globalEventHandler = NULL; + } + handlerRef->openFileCallback = NULL; + } +} + +static pascal OSErr handleOpenDocumentEvent(const AppleEvent* event, AppleEvent* reply, SRefCon handlerRefArg) +{ + LOG("Hey, handleOpenDocumentEvent() got called!\n"); + MacOpenFileHandler* handlerRef = (MacOpenFileHandler*)handlerRefArg; + + AEDescList docList; + OSErr result = AEGetParamDesc(event, keyDirectObject, typeAEList, &docList); + + if (result != noErr) + { + return result; + } + + long docCount = 0; + result = AECountItems(&docList, &docCount); + if (result != noErr) + { + return result; + } + + char buffer[2048]; + + // Yup, it's zero-indexed. Weird. + for (long i = 1; i <= docCount; i++) + { + AEKeyword keyword; + DescType docType; + Size docSize; + + result = AEGetNthPtr(&docList, i, typeFileURL, &keyword, &docType, &buffer, sizeof(buffer), &docSize); + + if (result != noErr) + { + LOG("Error getting event doc index %ld\n", i); + return result; + } + + CFURLRef docUrlRef = CFURLCreateWithBytes(NULL, (UInt8*)buffer, docSize, kCFStringEncodingUTF8, NULL); + + if (docUrlRef != NULL) + { + CFStringRef docStringRef = CFURLCopyFileSystemPath(docUrlRef, kCFURLPOSIXPathStyle); + if (docStringRef != NULL) + { + char pathBuffer[1024]; + if (CFStringGetFileSystemRepresentation(docStringRef, pathBuffer, sizeof(pathBuffer))) + { + handlerRef->openFileCallback(pathBuffer); + LOG("Successfully handled event?\n"); + } + CFRelease(docStringRef); + } + CFRelease(docUrlRef); + } + } + + return AEDisposeDesc(&docList); +} + +static OSStatus globalEventHandler(EventHandlerCallRef handler, EventRef event, void* data) +{ + LOG("globalEventHandler()!!!!!!\n"); + + bool inQueue = IsEventInQueue(GetMainEventQueue(), event); + + if (inQueue) + { + RetainEvent(event); + RemoveEventFromQueue(GetMainEventQueue(), event); + } + + EventRecord record; + ConvertEventRefToEventRecord(event, &record); + char messageStr[5] = + { + (char)((record.message >> 24) & 0xff), + (char)((record.message >> 16) & 0xff), + (char)((record.message >> 8) & 0xff), + (char)((record.message) & 0xff), + 0, + }; + LOG("globalEventHandler() what=%hu, message=%s\n", record.what, messageStr); + OSStatus result = AEProcessAppleEvent(&record); + + if (result == errAEEventNotHandled) + { + LOG("errAEEventNotHandled in globalEventHandler()\n"); + } + else if (result != noErr) + { + LOG("globalEventHandler() AEProcessAppleEvent() returned ERROR: %d (%s)\n", result, strerror(result)); + } + else + { + LOG("globalEventHandler() AEProcessAppleEvent() success!\n"); + } + + if (inQueue) + { + ReleaseEvent(event); + } + + return noErr; +} + diff --git a/tools/mac_events_test/makefile b/tools/mac_events_test/makefile new file mode 100644 index 000000000..00225e3ad --- /dev/null +++ b/tools/mac_events_test/makefile @@ -0,0 +1,218 @@ +# Makefile by Adam, 2022 + +################################################################################ +# What OS we're compiling on +################################################################################ + +IS_WSL := 0 +ifeq ($(OS),Windows_NT) + HOST_OS = Windows +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + HOST_OS = Linux + # Check if this is WSL. 0 for not WSL, 1 for WSL + IS_WSL := $(shell uname -a | grep -i WSL | wc -l) + else ifeq ($(UNAME_S),Darwin) + HOST_OS = Darwin + endif +endif + +################################################################################ +# Programs to use +################################################################################ + +CC = gcc + +FIND:=find + + +################################################################################ +# Source Files +################################################################################ + +SOURCES := main.c + +################################################################################ +# Includes +################################################################################ + +################################################################################ +# Compiler Flags +################################################################################ + +# These are flags for the compiler, all files +CFLAGS = \ + -c \ + -g \ + -fdiagnostics-color=always \ + -ffunction-sections \ + -fdata-sections \ + -gdwarf-4 \ + -ggdb \ + -O2 \ + -fno-jump-tables \ + -finline-functions \ + -std=gnu17 + +# Required for OpenGL and some other libraries +CFLAGS += \ + -mmacosx-version-min=10.0 + +# These are warning flags that the IDF uses +CFLAGS_WARNINGS = \ + -Wall \ + -Werror=all \ + -Wno-error=unused-function \ + -Wno-error=unused-variable \ + -Wno-error=deprecated-declarations \ + -Wextra \ + -Wno-unused-parameter \ + -Wno-sign-compare \ + -Wno-enum-conversion \ + -Wno-error=unused-but-set-variable + +# These are warning flags that I like +CFLAGS_WARNINGS_EXTRA = \ + -Wundef \ + -Wformat=2 \ + -Winvalid-pch \ + -Wmissing-format-attribute \ + -Wmissing-include-dirs \ + -Wpointer-arith \ + -Wunused-local-typedefs \ + -Wuninitialized \ + -Wshadow \ + -Wredundant-decls \ + -Wswitch \ + -Wcast-align \ + -Wformat-nonliteral \ + -Wno-switch-default \ + -Wunused \ + -Wunused-macros \ + -Wmissing-declarations \ + -Wmissing-prototypes \ + -Wcast-qual \ + -Wno-switch \ + -Wunused-result \ +# -Wstrict-prototypes \ +# -Wpedantic \ +# -Wconversion \ +# -Wsign-conversion \ +# -Wdouble-promotion + +################################################################################ +# Defines +################################################################################ + +# Create a variable with the git hash and branch name +GIT_HASH = \"$(shell git rev-parse --short=7 HEAD)\" + +# Used by the ESP SDK +DEFINES_LIST = \ + _GNU_SOURCE \ + _POSIX_READER_WRITER_LOCKS + +DEFINES = $(patsubst %, -D%, $(DEFINES_LIST)) + +################################################################################ +# Output Objects +################################################################################ + +# This is the directory in which object files will be stored +OBJ_DIR = obj + +# This is a list of objects to build +OBJECTS = $(patsubst %.c, $(OBJ_DIR)/%.o, $(SOURCES)) + +################################################################################ +# Linker options +################################################################################ + +# This is a list of libraries to include. Order doesn't matter + +#LIBS = m X11 GL pthread Xext Xinerama +LIBS = + +# These are directories to look for library files in +LIB_DIRS = + +# On MacOS we need to ensure that X11 is added for OpenGL and some others +#ifeq ($(HOST_OS),Darwin) +# LIB_DIRS = /opt/X11/lib +#endif + +# This combines the flags for the linker to find and use libraries +LIBRARY_FLAGS = $(patsubst %, -L%, $(LIB_DIRS)) $(patsubst %, -l%, $(LIBS)) \ + -ggdb + +LIBRARY_FLAGS += \ + -framework Carbon + +################################################################################ +# Build Filenames +################################################################################ + +# These are the files to build +EXECUTABLE = test +BUNDLE = test.app +ICONS = test.icns + +################################################################################ +# Targets for Building +################################################################################ + +# This list of targets do not build files which match their name +.PHONY: all bundle clean print-% + +# Build the executable +all: $(EXECUTABLE) + +# To build the main file, you have to compile the objects +$(EXECUTABLE): $(OBJECTS) + $(CC) $(OBJECTS) $(LIBRARY_FLAGS) -o $@ + +# This compiles each c file into an o file +./$(OBJ_DIR)/%.o: ./%.c + @mkdir -p $(@D) # This creates a directory before building an object in it. + $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CFLAGS_WARNINGS_EXTRA) $(DEFINES) $(INC) $< -o $@ + +bundle: $(BUNDLE) + +$(BUNDLE): $(EXECUTABLE) $(ICONS) Info.plist + rm -rf $(BUNDLE) + mkdir -p $(BUNDLE)/Contents/{MacOS,Resources,libs} + cp Info.plist $(BUNDLE)/Contents/Info.plist + echo "APPLTest" > $(BUNDLE)/Contents/PkgInfo + cp $(ICONS) $(BUNDLE)/Contents/Resources/ + vtool -set-build-version macos 10.0 10.0 -replace -output $(BUNDLE)/Contents/MacOS/test $(EXECUTABLE) + dylibbundler -od -b -x ./$(BUNDLE)/Contents/MacOS/test -d ./$(BUNDLE)/Contents/libs/ + + +$(ICONS): ../../emulator/resources/icon.png + rm -rf test.iconset + mkdir -p test.iconset + sips -z 16 16 $< --out test.iconset/icon_16x16.png + sips -z 32 32 $< --out test.iconset/icon_16x16@2x.png + sips -z 32 32 $< --out test.iconset/icon_32x32.png + sips -z 64 64 $< --out test.iconset/icon_32x32@2x.png + sips -z 128 128 $< --out test.iconset/icon_128x128.png + sips -z 256 256 $< --out test.iconset/icon_128x128@2x.png + sips -z 256 256 $< --out test.iconset/icon_256x256.png + sips -z 512 512 $< --out test.iconset/icon_256x256@2x.png + sips -z 512 512 $< --out test.iconset/icon_512x512.png + sips -z 1024 1024 $< --out test.iconset/icon_512x512@2x.png + iconutil -c icns -o $(ICONS) test.iconset + rm -r test.iconset + +# This cleans emulator files +clean: + -@rm -rf $(OBJECTS) $(EXECUTABLE) $(ICONS) test.iconset $(BUNDLE) + + +################################################################################ +# Firmware targets +################################################################################ + +# Print any value from this makefile +print-% : ; @echo $* = $($*)