Search code examples
premake

Premake doesn't picking up dependencies


Recently I've changed from CMake to Premake (v5.0.0-alpha8) and I'm not quite sure how to achieve the the following in Premake.

I want to include some dependencies so in CMake I can do something like this:

target_link_libraries(${PROJECT_NAME} 
    ${YALLA_ABS_PLATFORM}
    ${YALLA_LIBRARY})

The above will add the paths of these libraries (dir) to "Additional Include Directories" in the compiler and it will also add an entry (lib) to "Additional Dependencies" in the linker so I don't need to do anything special beyond calling target_link_libraries.

So I expected that when I'm doing something like this in Premake:

links {
    YALLA_LIBRARY
}

I'd get the same result but I don't.

I also tried to use the libdirs but it doesn't really work, I mean I can't see the library directory and its subdirectories passed to the compiler as "Additional Include Directories" (/I) or Yalla.Library.lib passed to the the linker as "Additional Dependencies".

Here is the directory structure I use:

.
|-- src
|   |-- launcher
|   |-- library
|   |   `-- utils
|   `-- platform
|       |-- abstract
|       `-- win32
`-- tests
    `-- platform
        `-- win32

The library dir is defined in Premake as follow:

project(YALLA_LIBRARY)
    kind "SharedLib"

    files {
        "utils/string-converter.hpp",
        "utils/string-converter.cpp",
        "defines.hpp"
    }

The platform dir is defined in Premake as follow:

project(YALLA_PLATFORM)
    kind "SharedLib"
    includedirs "abstract"

    links {
        YALLA_LIBRARY
    }

    if os.get() == "windows" then
        include     "win32"
    else
        return -- OS NOT SUPPORTED
    end

The win32 dir is defined in Premake as follow:

files {
    "event-loop.cpp",
    "win32-exception.cpp",
    "win32-exception.hpp",
    "win32-window.cpp",
    "win32-window.hpp",
    "window.cpp"
}

And finally at the root dir I have the following Premake file:

PROJECT_NAME = "Yalla"

-- Sets global constants that represents the projects' names
YALLA_LAUNCHER = PROJECT_NAME .. ".Launcher"
YALLA_LIBRARY = PROJECT_NAME .. ".Library"
YALLA_ABS_PLATFORM = PROJECT_NAME .. ".AbstractPlatform"
YALLA_PLATFORM = PROJECT_NAME .. ".Platform"

workspace(PROJECT_NAME)
    configurations  { "Release", "Debug" }
    flags           { "Unicode" }

    startproject    ( YALLA_LAUNCHER )
    location        ( "../lua_build" )

    include         "src/launcher"
    include         "src/library"
    include         "src/platform"

I'm probably misunderstanding how Premake works due to lack of experience with it.


Solution

  • I solved it by creating a new global function and named it includedeps.

    function includedeps(workspace, ...) 
        local workspace = premake.global.getWorkspace(workspace)
    
        local args = { ... }
        local args_count = select("#", ...)
        local func = select(args_count, ...)
    
        if type(func) == "function" then
            args_count = args_count - 1
            args = table.remove(args, args_count)
        else
            func = nil
        end
    
        for i = 1, args_count do
            local projectName = select(i, ...)
            local project = premake.workspace.findproject(workspace, projectName)
            if project then
                local topIncludeDir, dirs = path.getdirectory(project.script)
                if func then 
                    dirs = func(topIncludeDir)
                else
                    dirs = os.matchdirs(topIncludeDir .. "/**")
                    table.insert(dirs, topIncludeDir)
                end
                includedirs(dirs)
                if premake.project.iscpp(project) then
                    libdirs(dirs)    
                end
                links(args)
            else
                error(string.format("project '%s' does not exist.", projectName), 3)
            end
        end
    end
    

    Usage:

    includedeps(PROJECT_NAME, YALLA_LIBRARY)
    

    or

    includedeps(PROJECT_NAME, YALLA_PLATFORM, function(topIncludeDir)
                return { path.join(topIncludeDir, "win32") }
            end)
    

    Update:

    For this to work properly you need to make sure that when you include the dependencies they are included by their dependency order and not by the order of the directory structure.

    So for example if I have the following dependency graph launcher --> platform --> library then I'll have to include them in the following order.

    include         "src/library"
    include         "src/platform"
    include         "src/launcher"
    

    As opposed to the directory structure that in my case is as follow:

    src/launcher
    src/library
    src/platform
    

    If you will include them by their directory structure it will fail and tell you that "The project 'Yalla.Platform' does not exist."