//-------------------------------------------------------------------------------------------------- static void GenerateApiBindConfig ( std::ofstream& cfgStream, ///< Stream to send the configuration to. legato::App& app, ///< The application being built. const legato::ExeToExeApiBind& binding ///< Binding to internal exe.component.interface. ) //-------------------------------------------------------------------------------------------------- { const std::string& clientInterfaceId = binding.ClientInterface(); std::string clientServiceName; // If the binding is a wildcard binding (applies to everything with a given service name), if (clientInterfaceId.compare(0, 2, "*.") == 0) { // Strip off the "*." wildcard specifier to get the service name. clientServiceName = clientInterfaceId.substr(2); } // Otherwise, look-up the client interface and take the service name from there. else { const auto& interface = app.FindClientInterface(clientInterfaceId); clientServiceName = interface.ExternalName(); } GenerateSingleApiBindingToApp( cfgStream, clientServiceName, app.Name(), binding.ServerInterface() ); }
//-------------------------------------------------------------------------------------------------- static void PrintWarning ( const legato::App& app, const std::string& warning ) //-------------------------------------------------------------------------------------------------- { std::cerr << "** Warning: application '" << app.Name() << "': " << warning << std::endl; }
//-------------------------------------------------------------------------------------------------- static void GenerateAppLimitsConfig ( std::ofstream& cfgStream, const legato::App& app ) //-------------------------------------------------------------------------------------------------- { if (app.IsSandboxed() == false) { cfgStream << " \"sandboxed\" !f" << std::endl; } if (app.StartMode() == legato::App::MANUAL) { cfgStream << " \"startManual\" !t" << std::endl; } cfgStream << " \"maxThreads\" [" << app.MaxThreads().Get() << "]" << std::endl; cfgStream << " \"maxMQueueBytes\" [" << app.MaxMQueueBytes().Get() << "]" << std::endl; cfgStream << " \"maxQueuedSignals\" [" << app.MaxQueuedSignals().Get() << "]" << std::endl; cfgStream << " \"maxMemoryBytes\" [" << app.MaxMemoryBytes().Get() << "]" << std::endl; cfgStream << " \"cpuShare\" [" << app.CpuShare().Get() << "]" << std::endl; if (app.MaxFileSystemBytes().IsSet()) { // This is not supported for unsandboxed apps. if (app.IsSandboxed() == false) { std::cerr << "**** Warning: File system size limit being ignored for unsandboxed" << " application '" << app.Name() << "'." << std::endl; } else { cfgStream << " \"maxFileSystemBytes\" [" << app.MaxFileSystemBytes().Get() << "]" << std::endl; } } if (app.WatchdogTimeout().IsSet()) { cfgStream << " \"watchdogTimeout\" [" << app.WatchdogTimeout().Get() << "]" << std::endl; } if (app.WatchdogAction().IsSet()) { cfgStream << " \"watchdogAction\" \"" << app.WatchdogAction().Get() << "\"" << std::endl; } }
//-------------------------------------------------------------------------------------------------- static void GenerateProcessEnvVarsConfig ( std::ofstream& cfgStream, const legato::App& app, const legato::ProcessEnvironment& procEnv ) //-------------------------------------------------------------------------------------------------- { // The PATH environment variable has to be handled specially. If no PATH variable is // specified in the .adef, we must provide one. bool pathSpecified = false; // Any environment variables are declared under a node called "envVars". // Each env var has its own node, with the name of the node being the name of // the environment variable. cfgStream << " \"envVars\"" << std::endl; cfgStream << " {" << std::endl; for (const auto& pair : procEnv.EnvVarList()) { if (pair.first == "PATH") { pathSpecified = true; } cfgStream << " \"" << pair.first << "\" \"" << pair.second << "\"" << std::endl; } if (!pathSpecified) { // The default path depends on whether the application is sandboxed or not. std::string path = "/usr/local/bin:/usr/bin:/bin"; if (app.IsSandboxed() == false) { path = "/opt/legato/apps/" + app.Name() + "/bin:" + path; } cfgStream << " \"PATH\" \"" << path << "\"" << std::endl; } cfgStream << " }" << std::endl; }
//-------------------------------------------------------------------------------------------------- static void GenerateSystemConfig ( const std::string& stagingDirPath, ///< Path to the root of the app's staging directory. legato::App& app, ///< The app to generate the configuration for. const legato::BuildParams_t& buildParams ///< Build parameters, such as the "is verbose" flag. ) //-------------------------------------------------------------------------------------------------- { // TODO: Rename this file to something that makes more sense (like "system.cfg", because it // gets installed in the "system" config tree). std::string path = stagingDirPath + "/root.cfg"; if (buildParams.IsVerbose()) { std::cout << "Generating system configuration data for app '" << app.Name() << "' in file '" << path << "'." << std::endl; } std::ofstream cfgStream(path, std::ofstream::trunc); cfgStream << "{" << std::endl; GenerateAppVersionConfig(cfgStream, app); GenerateAppLimitsConfig(cfgStream, app); GenerateGroupsConfig(cfgStream, app); GenerateFileMappingConfig(cfgStream, app); GenerateProcessConfig(cfgStream, app); GenerateIpcBindingConfig(cfgStream, app, buildParams); GenerateConfigTreeAclConfig(cfgStream, app); cfgStream << "}" << std::endl; }
//-------------------------------------------------------------------------------------------------- void ApplicationBuilder_t::Build ( legato::App& app, std::string outputDirPath ///< Directory into which the generated app bundle should be put. ) //-------------------------------------------------------------------------------------------------- { CheckForLimitsConflicts(app); // Construct the working directory structure, which consists of an "work" directory and // a "staging" directory. Inside the "staging" directory, there is "lib", "bin", and any // other directories required to hold files bundled by the application or one of its components. // The "work" directory is for intermediate build output, like generated .c files and .o files. // The "staging" directory will get tar-compressed to become the actual application file. if (m_Params.IsVerbose()) { std::cout << "Creating working directories under '" << m_Params.ObjOutputDir() << "'." << std::endl; } legato::BuildParams_t buildParams(m_Params); const std::string& stagingDirPath = m_Params.StagingDir(); buildParams.LibOutputDir(stagingDirPath + "/lib"); buildParams.ExeOutputDir(stagingDirPath + "/bin"); buildParams.ObjOutputDir(m_Params.ObjOutputDir() + "/work"); // Clean the staging area. legato::CleanDir(stagingDirPath); // Create directories. legato::MakeDir(buildParams.ObjOutputDir()); legato::MakeDir(buildParams.LibOutputDir()); legato::MakeDir(buildParams.ExeOutputDir()); // Build all the components in the application, each with its own working directory // to avoid file name conflicts between .o files in different components, and copy all // generated and bundled files into the application staging area. // NOTE: Components have to be built before any other components that depend on them. // They also need to be bundled into the app in the same order, so that higher-layer // components can override files bundled by lower-layer components. ComponentBuilder_t componentBuilder(buildParams); auto& map = app.ComponentMap(); for (auto& mapEntry : map) { auto& componentPtr = mapEntry.second; BuildAndBundleComponent(*componentPtr, componentBuilder, buildParams.ObjOutputDir()); } // Build all the executables and their IPC libs. BuildExecutables(app, buildParams); // Copy in any bundled files and directories from the "bundles:" section of the .adef. // Note: do the directories first, in case the files list adds files to those directories. for (auto& fileMapping : app.BundledDirs()) { mk::CopyToStaging( fileMapping.m_SourcePath, stagingDirPath, fileMapping.m_DestPath, m_Params.IsVerbose() ); } for (auto& fileMapping : app.BundledFiles()) { mk::CopyToStaging( fileMapping.m_SourcePath, stagingDirPath, fileMapping.m_DestPath, m_Params.IsVerbose() ); } // Generate the app-specific configuration data that tells the framework what limits to place // on the app when it is run, etc. GenerateSystemConfig(stagingDirPath, app, m_Params); // TODO: Generate the application's configuration tree (containing all its pool sizes, // and anything else listed under the "config:" section of the .adef.) // TODO: Copy in the metadata (.adef and Component.cdef) files so they can be retrieved // by Developer Studio. // Zip it all up. std::string outputPath = legato::CombinePath( outputDirPath, app.Name() + "." + buildParams.Target() ); if (!legato::IsAbsolutePath(outputPath)) { outputPath = legato::GetWorkingDir() + "/" + outputPath; } std::string tarCommandLine = "tar cjf \"" + outputPath + "\" -C \"" + stagingDirPath + "\" ."; if (m_Params.IsVerbose()) { std::cout << "Packaging application into '" << outputPath << "'." << std::endl; std::cout << std::endl << "$ " << tarCommandLine << std::endl << std::endl; } mk::ExecuteCommandLine(tarCommandLine); }