BuildInfo *LSCompiler::loadBuildFile(const utString& cref) { for (UTsize i = 0; i < sourcePath.size(); i++) { utString path = sourcePath.at(i); path += platform_getFolderDelimiter(); path += cref; if (!strstr(cref.c_str(), ".build")) { path += ".build"; } utFileStream stream; stream.open(path.c_str(), utStream::SM_READ); if (stream.isOpen()) { stream.close(); BuildInfo *buildInfo = BuildInfo::parseBuildFile(path.c_str()); return buildInfo; } } return NULL; }
const char *platform_normalizePath(const char *path) { static char npath[4096]; int i; int nlen; char delimiter; nlen = strlen(path); if (nlen > 4000) { return ""; } strcpy(npath, path); delimiter = platform_getFolderDelimiter()[0]; for (i = 0; i < nlen; i++) { if ((npath[i] == '\\') || (npath[i] == '/')) { npath[i] = delimiter; } } return npath; }
void LSCompiler::generateRootDependenciesRecursive(const utString& ref) { // We're either going to be compiling against an existing loom assembly // or compiling from a build file char cref[2048]; snprintf(cref, 2048, "%s", ref.c_str()); if (strstr(cref, ".loomlib")) { *(strstr(cref, ".loomlib")) = 0; } for (UTsize i = 0; i < rootBuildDependencies.size(); i++) { BuildInfo *buildInfo = rootBuildDependencies.at(i); if (buildInfo->getAssemblyName() == cref) { return; } } // first look in the src folders for an existing build file BuildInfo *buildInfo = loadBuildFile(cref); if (buildInfo) { utString assemblyLib = buildInfo->getOutputDir() + platform_getFolderDelimiter() + buildInfo->getAssemblyName() + ".loomlib"; // If the assembly is not built yet, build it if (!platform_mapFileExists(assemblyLib.c_str())) { for (UTsize i = 0; i < buildInfo->getNumReferences(); i++) { utString rref = buildInfo->getReference(i); generateRootDependenciesRecursive(rref); } rootBuildDependencies.push_back(buildInfo); } else { rootLibDependencies.push_back(ref); } } if (rootDependencies.find(ref) == UT_NPOS) { if (!buildInfo) { // we're compiling against a .loomlib and won't be rebuilding it rootLibDependencies.push_back(ref); } rootDependencies.push_back(ref); } }
// Take a snapshot of the state of all our tracked files. This snapshot can // then be compared to identify changes. static utArray<FileEntry> *generateFileState(const char *root) { utArray<FileEntry> *list = lmNew(NULL) utArray<FileEntry>(); // Walk files in assets and src. char buffer[2048]; sprintf(buffer, "%s%s%s", root, platform_getFolderDelimiter(), "assets"); platform_walkFiles(buffer, handleFileStateWalkCallback, list); sprintf(buffer, "%s%s%s", root, platform_getFolderDelimiter(), "src"); platform_walkFiles(buffer, handleFileStateWalkCallback, list); sprintf(buffer, "%s%s%s", root, platform_getFolderDelimiter(), "bin"); platform_walkFiles(buffer, handleFileStateWalkCallback, list); // Sort the list into canonical order. list->sort(compareFileEntryBool); // Return the list. return list; }
void LSCompiler::linkRootAssembly(const utString& sjson) { json_error_t jerror; json_t *json = json_loadb((const char *)sjson.c_str(), sjson.length(), 0, &jerror); lmAssert(json, "Error linking assembly"); json_t *ref_array = json_object_get(json, "references"); lmAssert(json, "Error linking assembly, can't get executable references"); for (UTsize i = 0; i < rootBuildDependencies.size(); i++) { BuildInfo *buildInfo = rootBuildDependencies.at(i); utString assemblySource = buildInfo->getOutputDir() + platform_getFolderDelimiter() + buildInfo->getAssemblyName() + ".loomlib"; utArray<unsigned char> rarray; lmAssert(utFileStream::tryReadToArray(assemblySource, rarray), "Unable to load library assembly %s", assemblySource.c_str()); utBase64 base64 = utBase64::encode64(rarray); for (size_t j = 0; j < json_array_size(ref_array); j++) { json_t *jref = json_array_get(ref_array, j); utString jname = json_string_value(json_object_get(jref, "name")); if (buildInfo->getAssemblyName() == jname) { logVerbose("Linking: %s", jname.c_str()); json_object_set(jref, "binary", json_string(base64.getBase64().c_str())); json_object_set(jref, "uid", json_string(readAssemblyUID(rarray))); break; } } } // filter the reference array by the import assemblies utStack<int> filter; for (size_t j = 0; j < json_array_size(ref_array); j++) { json_t *jref = json_array_get(ref_array, j); utString jname = json_string_value(json_object_get(jref, "name")); bool found = false; // always find the System assembly, so we don't have to explicitly import from it if (jname == "System") { found = true; } for (UTsize k = 0; k < importedAssemblies.size() && !found; k++) { if (importedAssemblies.at(k)->getName() == jname) { found = true; break; } } if (!found) { filter.push((int)j); } } while (filter.size()) { json_array_remove(ref_array, filter.pop()); } for (UTsize i = 0; i < rootLibDependencies.size(); i++) { utString libName = rootLibDependencies.at(i); for (size_t j = 0; j < json_array_size(ref_array); j++) { json_t *jref = json_array_get(ref_array, j); utString jname = json_string_value(json_object_get(jref, "name")); if (libName != jname) { continue; } log("Linking: %s", libName.c_str()); utString delim = platform_getFolderDelimiter(); utString libPath = sdkPath + delim + "libs" + delim + libName + ".loomlib"; utArray<unsigned char> rarray; if (libName == "System" && embeddedSystemAssembly) { size_t embeddedSystemAssemblyLength = strlen(embeddedSystemAssembly); rarray.resize((int)(embeddedSystemAssemblyLength + 1)); memcpy(&rarray[0], embeddedSystemAssembly, embeddedSystemAssemblyLength + 1); } else { lmAssert(utFileStream::tryReadToArray(libPath, rarray), "Unable to load library assembly %s at %s", libName.c_str(), libPath.c_str()); } utBase64 base64 = utBase64::encode64(rarray); json_object_set(jref, "binary", json_string(base64.getBase64().c_str())); json_object_set(jref, "uid", json_string(readAssemblyUID(rarray))); break; } } json_object_set(json, "executable", json_true()); utString execSource = rootBuildInfo->getOutputDir() + utString(platform_getFolderDelimiter()) + rootBuildInfo->getAssemblyName() + ".loom"; // generate binary assembly for executable BinWriter::writeExecutable(execSource.c_str(), json); log("Compile Successful: %s\n", execSource.c_str()); }
void LSCompiler::compileAssembly(BuildInfo *buildInfo) { clearImports(); log("Compiling: %s", buildInfo->getAssemblyName().c_str()); LSCompiler *compiler = new LSCompiler(); // open a new (isolated) compiler VM compiler->openCompilerVM(); compiler->vm->setCompiling(true); // parses the build file, parses source files, generates AST, etc compiler->buildInfo = buildInfo; // let the buildInfo know we are debug compiler->buildInfo->setDebugBuild(debugBuild); // build 1st pass assembly which contains type signatures but no code AssemblyBuilder *ab = AssemblyBuilder::create(compiler->buildInfo); utString typesAssembly; // write out temporary assembly ab->writeToString(typesAssembly); //load the type signature assembly into our VM (also loads any references) Assembly *assembly = compiler->vm->loadTypeAssembly(typesAssembly); // compile all modules (types) compiler->compileModules(); // dump any errors/warnings LSCompilerLog::dump(); // if we have any compiler errors, exit if (LSCompilerLog::getNumErrors()) { exit(EXIT_FAILURE); } LSCompilerLog::clear(); ab->setAssembly(assembly); // inject type information ab->injectTypes(assembly); // inject byte code into assembly builder ab->injectByteCode(assembly); // write out final assembly utString outputDir = compiler->buildInfo->getOutputDir(); utString ext = ".loom"; if (compiler->buildInfo->isExecutable()) { processExecutableConfig(ab); utString json; ab->writeToString(json); // output a loom lib for IDE's to consume if (dumpSymbols) { utString jsonFileName; if (outputDir.length()) { jsonFileName = outputDir + platform_getFolderDelimiter() + compiler->buildInfo->getAssemblyName() + ".symbols"; } else { jsonFileName = compiler->buildInfo->getAssemblyName() + ".symbols"; } ab->writeToFile(jsonFileName); log("Symbols Generated: %s", jsonFileName.c_str()); } // finally link the root assembly linkRootAssembly(json); } else { utString jsonFileName; ext = ".loomlib"; if (outputDir.length()) { jsonFileName = outputDir + platform_getFolderDelimiter() + compiler->buildInfo->getAssemblyName() + ext; } else { jsonFileName = compiler->buildInfo->getAssemblyName() + ext; } ab->writeToFile(jsonFileName); } compiler->vm->setCompiling(false); // shut 'er down! compiler->closeCompilerVM(); delete compiler; }