Beispiel #1
0
//--------------------------------------------------------------------------------------------------
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);
}