/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018, 2019, 2020 * Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFApplication.h" #import "OFArray.h" #import "OFFile.h" #import "OFXMLAttribute.h" #import "OFXMLElement.h" #import "OFInvalidFormatException.h" #import "OFUnsupportedVersionException.h" #import "copyright.h" @interface LibraryGenerator: OFObject @end OF_APPLICATION_DELEGATE(LibraryGenerator) @implementation LibraryGenerator - (void)applicationDidFinishLaunching { [self generateLinkLibInDirectory: @"../../src/runtime"]; [OFApplication terminate]; } - (void)generateLinkLibInDirectory: (OFString *)directory { OFXMLElement *library = [OFXMLElement elementWithFile: [directory stringByAppendingPathComponent: @"library.xml"]]; OFString *linklibPath = [[directory stringByAppendingPathComponent: @"linklib"] stringByAppendingPathComponent: @"linklib.m"]; OFFile *linklib = [OFFile fileWithPath: linklibPath mode: @"w"]; OFArray OF_GENERIC(OFXMLElement *) *functions; size_t funcIndex = 0; OFString *libBase; if (![library.name isEqual: @"amiga-library"] || library.namespace != nil) @throw [OFInvalidFormatException exception]; OFXMLAttribute *version = [library attributeForName: @"version"]; if (version == nil) @throw [OFInvalidFormatException exception]; if (![version.stringValue isEqual: @"1.0"]) @throw [OFUnsupportedVersionException exceptionWithVersion: version.stringValue]; libBase = [library attributeForName: @"base"].stringValue; [linklib writeString: COPYRIGHT]; [linklib writeString: @"/* This file is automatically generated from library.xml */\n" @"\n" @"#include \"config.h\"\n" @"\n"]; for (OFXMLElement *include in [library elementsForName: @"include"]) [linklib writeFormat: @"#import \"%@\"\n", include.stringValue]; [linklib writeFormat: @"\n" @"extern struct Library *%@;\n" @"\n", libBase]; functions = [library elementsForName: @"function"]; for (OFXMLElement *function in functions) { OFString *name = [function attributeForName: @"name"].stringValue; OFString *returnType = [function attributeForName: @"return-type"].stringValue; OFArray OF_GENERIC(OFXMLElement *) *arguments = [function elementsForName: @"argument"]; size_t argumentIndex; if (returnType == nil) returnType = @"void"; [linklib writeFormat: @"%@\n%@(", returnType, name]; argumentIndex = 0; for (OFXMLElement *argument in [function elementsForName: @"argument"]) { OFString *argName = [argument attributeForName: @"name"].stringValue; OFString *argType = [argument attributeForName: @"type"].stringValue; if (argumentIndex++ > 0) [linklib writeString: @", "]; [linklib writeString: argType]; if (![argType hasSuffix: @"*"]) [linklib writeString: @" "]; [linklib writeString: argName]; } [linklib writeFormat: @")\n" @"{\n" @"#if defined(OF_AMIGAOS_M68K)\n" @"\tregister struct Library *a6 __asm__(\"a6\") = %@;\n" @"\t(void)a6;\n" @"\t", libBase]; if (![returnType isEqual: @"void"]) [linklib writeString: @"return "]; [linklib writeString: @"(("]; [linklib writeString: returnType]; if (![returnType hasSuffix: @"*"]) [linklib writeString: @" "]; [linklib writeString: @"(*)("]; argumentIndex = 0; for (OFXMLElement *argument in arguments) { OFString *argType = [argument attributeForName: @"type"].stringValue; OFString *m68kReg = [argument attributeForName: @"m68k-reg"].stringValue; if (argumentIndex++ > 0) [linklib writeString: @", "]; [linklib writeString: argType]; if (![argType hasSuffix: @"*"]) [linklib writeString: @" "]; [linklib writeFormat: @"__asm__(\"%@\")", m68kReg]; } [linklib writeFormat: @"))(((uintptr_t)%@) - %zu))(", libBase, 30 + funcIndex * 6]; argumentIndex = 0; for (OFXMLElement *argument in [function elementsForName: @"argument"]) { OFString *argName = [argument attributeForName: @"name"].stringValue; if (argumentIndex++ > 0) [linklib writeString: @", "]; [linklib writeString: argName]; } [linklib writeFormat: @");\n" @"#elif defined(OF_MORPHOS)\n" @"\t__asm__ __volatile__ (\n" @"\t \"mr\t\t%%%%r12, %%0\"\n" @"\t :: \"r\"(%@) : \"r12\"\n" @"\t);\n" @"\n" @"\t", libBase, libBase]; if (![returnType isEqual: @"void"]) [linklib writeString: @"return "]; [linklib writeString: @"(("]; [linklib writeString: returnType]; if (![returnType hasSuffix: @"*"]) [linklib writeString: @" "]; [linklib writeString: @"(*)("]; argumentIndex = 0; for (OFXMLElement *argument in arguments) { OFString *argType = [argument attributeForName: @"type"].stringValue; if (argumentIndex++ > 0) [linklib writeString: @", "]; [linklib writeString: argType]; } [linklib writeFormat: @"))*(void **)(((uintptr_t)%@) - %zu))(", libBase, 28 + funcIndex * 6]; argumentIndex = 0; for (OFXMLElement *argument in [function elementsForName: @"argument"]) { OFString *argName = [argument attributeForName: @"name"].stringValue; if (argumentIndex++ > 0) [linklib writeString: @", "]; [linklib writeString: argName]; } [linklib writeString: @");\n" @"#endif\n"]; if ([function attributeForName: @"noreturn"] != nil) [linklib writeString: @"\n\tOF_UNREACHABLE\n"]; [linklib writeString: @"}\n"]; if (++funcIndex < functions.count) [linklib writeString: @"\n"]; } } @end