//-------------------------------------------------------------------------------------------------- static void GetCommandLineArgs ( int argc, const char** argv ) //-------------------------------------------------------------------------------------------------- { // The target device (e.g., "ar7"). std::string target = "localhost"; // Non-zero = say what we are doing on stdout. bool isVerbose = false; // Full path of the library file to be generated. "" = use default file name. std::string buildOutputPath = ""; // Path to the directory where generated runtime libs should be put. std::string libOutputDir = "."; // Path to the directory where intermediate build output files (such as generated // source code and object code files) should be put. std::string objOutputDir = "."; std::string cFlags; // C compiler flags. std::string cxxFlags; // C++ compiler flags. std::string ldFlags; // Linker flags. // Lambda function that gets called once for each occurence of the --cflags (or -C) // argument on the command line. auto cFlagsPush = [&](const char* arg) { cFlags += " "; cFlags += arg; }; // Lambda function that gets called for each occurence of the --cxxflags, (or -X) argument on // the command line. auto cxxFlagsPush = [&](const char* arg) { cxxFlags += " "; cxxFlags += arg; }; // Lambda function that gets called once for each occurence of the --ldflags (or -L) // argument on the command line. auto ldFlagsPush = [&](const char* arg) { ldFlags += " "; ldFlags += arg; }; // Lambda functions for handling arguments that can appear more than once on the // command line. auto interfaceDirPush = [&](const char* path) { BuildParams.AddInterfaceDir(path); }; auto sourceDirPush = [&](const char* path) { BuildParams.AddSourceDir(path); }; // Lambda function that gets called once for each occurence of a component path on the // command line. auto componentPathSet = [&](const char* param) { static bool matched = false; if (matched) { throw legato::Exception("Only one component allowed. First is '" + Component.Path() + "'. Second is '" + param + "'."); } matched = true; Component.Path(param); }; // Register all our arguments with the argument parser. le_arg_AddOptionalString(&buildOutputPath, "", 'o', "output-path", "Specify the complete path name of the component library to be built."); le_arg_AddOptionalString(&libOutputDir, ".", 'l', "lib-output-dir", "Specify the directory into which any generated runtime libraries" " should be put. (This option ignored if -o specified.)"); le_arg_AddOptionalString(&objOutputDir, "./_build", 'w', "object-dir", "Specify the directory into which any intermediate build artifacts" " (such as .o files and generated source code files) should be put."); le_arg_AddOptionalString(&target, "localhost", 't', "target", "Specify the target device to build for (localhost | ar7)."); le_arg_AddMultipleString('i', "interface-search", "Add a directory to the interface search path.", interfaceDirPush); le_arg_AddMultipleString('c', "component-search", "(DEPRECATED) Add a directory to the source search path (same as -s).", sourceDirPush); le_arg_AddMultipleString('s', "source-search", "Add a directory to the source search path.", sourceDirPush); le_arg_AddOptionalFlag(&isVerbose, 'v', "verbose", "Set into verbose mode for extra diagnostic information."); le_arg_AddMultipleString('C', "cflags", "Specify extra flags to be passed to the C compiler.", cFlagsPush); le_arg_AddMultipleString('X', "cxxflags", "Specify extra flags to be passed to the C++ compiler.", cxxFlagsPush); le_arg_AddMultipleString('L', "ldflags", "Specify extra flags to be passed to the linker when linking " "executables.", ldFlagsPush); le_arg_AddOptionalFlag(&IsStandAlone, 'a', "stand-alone", "Create IPC interface instance libraries for APIs required by" " the component and link the component library with those interface" " libraries, so that the component library can be loaded and run" " without the help of mkexe or mkapp. This is useful when integrating" " with third-party code that uses some other build system." ); // Any remaining parameters on the command-line are treated as a component path. // Note: there should only be one. le_arg_SetLooseParamHandler(componentPathSet); // Scan the arguments now. le_arg_Scan(argc, argv); // Were we given a component? if (Component.Name() == "") { throw std::runtime_error("A component must be supplied on the command line."); } // Add the current working directory to the list of source search directories and the // list of interface search directories. BuildParams.AddSourceDir("."); BuildParams.AddInterfaceDir("."); // Store other build params specified on the command-line. if (isVerbose) { BuildParams.SetVerbose(); } BuildParams.SetTarget(target); BuildParams.LibOutputDir(libOutputDir); BuildParams.ObjOutputDir(objOutputDir); BuildParams.CCompilerFlags(cFlags); BuildParams.CxxCompilerFlags(cxxFlags); BuildParams.LinkerFlags(ldFlags); if (buildOutputPath != "") { Component.Lib().BuildOutputPath(buildOutputPath); } }
//-------------------------------------------------------------------------------------------------- void ComponentBuilder_t::Build ( const legato::Component& component ///< The component whose library is to be built. ) //-------------------------------------------------------------------------------------------------- { // Essentially, when we build a component, we use gcc to build a library (.so) from a bunch // of C source code files. The library goes into the component's library output directory. // TODO: Check if files need recompiling. Maybe change to use intermediate .o files // to break up compiling so it runs faster for large components that have had // only small changes to them. std::stringstream commandLine; commandLine << mk::GetCompilerPath(m_Params.Target()); // Specify the output file path. // TODO: Add a version number to the library. std::string libPath = m_Params.LibOutputDir() + "/lib" + component.Name() + ".so"; if (m_Params.IsVerbose()) { std::cout << "Building component library '" << libPath << "'." << std::endl; } commandLine << " -o " << libPath << " -shared" << " -fPIC" << " -Wall" << " -Werror"; // Add the include paths specified on the command-line. for (auto i : m_Params.InterfaceDirs()) { commandLine << " -I" << i; } // Add the include paths specific to the component. for (auto i : component.IncludePath()) { commandLine << " -I" << i; } // Define the component name, log session variable, and log filter variable. commandLine << " -DLEGATO_COMPONENT=" << component.CName(); commandLine << " -DLE_LOG_SESSION=" << component.Name() << "_LogSession "; commandLine << " -DLE_LOG_LEVEL_FILTER_PTR=" << component.Name() << "_LogLevelFilterPtr "; // Define the COMPONENT_INIT. commandLine << " \"-DCOMPONENT_INIT=void " << mk::GetComponentInitName(component) << "()\""; // Add the CFLAGS to the command-line. commandLine << " " << m_Params.CCompilerFlags(); // Add the list of C source code files. if (component.CSourcesList().empty()) { throw legato::Exception("Component '" + component.Name() + "' has no source files."); } for (const auto& sourceFile : component.CSourcesList()) { commandLine << " \"" ; if ((component.Path() != "") && (!legato::IsAbsolutePath(sourceFile))) { commandLine << component.Path() << "/" << sourceFile; } else { commandLine << sourceFile; } commandLine << "\"" ; } // Run the command. if (m_Params.IsVerbose()) { std::cout << commandLine.str() << std::endl; } mk::ExecuteCommandLine(commandLine); }