Skip to content

Commit

Permalink
Expose export-compile-commands in premake5 project.
Browse files Browse the repository at this point in the history
Minor fix in Sys::getOSArchitecture.
  • Loading branch information
SpartanJ committed Oct 18, 2024
1 parent 8ff5245 commit 46b2a1b
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 7 deletions.
44 changes: 44 additions & 0 deletions premake/export-compile-commands/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## Generate compile_commands.json for premake projects

This module implements [JSON Compilation Database Format
Specification](http://clang.llvm.org/docs/JSONCompilationDatabase.html) for
premake projects.

Install this module somewhere premake can find it, for example:

```
git clone https://github.com/tarruda/premake-export-compile-commands export-compile-commands
```

Then put this at the top of your system script(eg: ~/.premake/premake-system.lua):

```lua
require "export-compile-commands"
```

Note that while possible, it is not recommended to put the `require` line in
project-specific premake configuration because the "export-compile-commands"
module will need to be installed everywhere your project is built.

After the above steps, the "export-compile-commands" action will be available
for your projects:

```
premake5 export-compile-commands
```

The `export-compile-commands` action will generate one json file per
config/platform combination in each workspace, all under the `compile_commands`
subdirectory. For example, say you have defined `debug` and `release`
configurations with `x32` and `x64` platforms, the output will be something
like:

```
Generated WORKSPACE_BUILD_DIR/compile_commands/debug_x32.json...
Generated WORKSPACE_BUILD_DIR/compile_commands/debug_x64.json...
Generated WORKSPACE_BUILD_DIR/compile_commands/release_x32.json...
Generated WORKSPACE_BUILD_DIR/compile_commands/release_x64.json...
```

where each file contain the compilation commands for the corresponding
config/platform combo.
4 changes: 4 additions & 0 deletions premake/export-compile-commands/_manifest.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
return {
'_preload.lua',
'export-compile-commands.lua',
}
3 changes: 3 additions & 0 deletions premake/export-compile-commands/_preload.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
return function(cfg)
return _ACTION == 'export-compile-commands'
end
210 changes: 210 additions & 0 deletions premake/export-compile-commands/export-compile-commands.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
local p = premake

p.modules.export_compile_commands = {}
local m = p.modules.export_compile_commands

local workspace = p.workspace
local project = p.project

local function esc(s)
s = s:gsub('\\', '\\\\')
s = s:gsub('"', '\\"')
return s
end

local function esc_table(t)
local res = {}
for k, v in pairs(t) do
table.insert(res, esc(v))
end
return res
end

local function quote(s)
return '"' .. esc(s) .. '"'
end

function m.getToolset(cfg)
return p.tools[cfg.toolset or 'gcc']
end

function m.getCommonFlags(prj, cfg)
-- some tools that consumes compile_commands.json have problems with relative include paths
relative = project.getrelative
project.getrelative = function(prj, dir) return dir end

local toolset = m.getToolset(cfg)
local flags = toolset.getcppflags(cfg)
flags = table.join(flags, toolset.getdefines(cfg.defines))
flags = table.join(flags, toolset.getundefines(cfg.undefines))
flags = table.join(flags, toolset.getincludedirs(cfg, cfg.includedirs, cfg.externalincludedirs))
flags = table.join(flags, toolset.getforceincludes(cfg))
if project.iscpp(prj) then
flags = table.join(flags, toolset.getcxxflags(cfg))
elseif project.isc(prj) then
flags = table.join(flags, toolset.getcflags(cfg))
end
flags = table.join(flags, cfg.buildoptions)
project.getrelative = relative
return flags
end

function m.getObjectPath(prj, cfg, node)
return path.join(cfg.objdir, path.appendExtension(node.objname, '.o'))
end

function m.getDependenciesPath(prj, cfg, node)
return path.join(cfg.objdir, path.appendExtension(node.objname, '.d'))
end

function m.getFileFlags(prj, cfg, node)
return table.join(m.getCommonFlags(prj, cfg), {
'-o', quote(m.getObjectPath(prj, cfg, node)),
'-MF', quote(m.getDependenciesPath(prj, cfg, node)),
'-c', quote(node.abspath)
})
end

local function computesystemincludepaths(tool, iscfile)
local cmd = tool .. " -E -v -fsyntax-only " .. (iscfile and '-x c' or '-x c++') .. ' "' .. _MAIN_SCRIPT .. '"' -- Use script as dummy "c" file
local s,e = os.outputof(cmd, "both")
if not s or not e then return {} end
local s = string.match(s, "#include <...> search starts here:\n(.*)End of search list.\n")
local includepaths = {}
for w in string.gmatch(s, " *([^\n]+) *") do
table.insert(includepaths, path.normalize(w))
end
return includepaths
end

local systemincludepathscache = {}

local function getsystemincludepaths(tool, iscfile)
if not systemincludepathscache[tool] then systemincludepathscache[tool] = {} end
local toolcache = systemincludepathscache[tool]
if not toolcache[iscfile] then toolcache[iscfile] = computesystemincludepaths(tool, iscfile) end
return toolcache[iscfile]
end

local function getsystemflags(tool, iscfile)
return table.implode(getsystemincludepaths(tool, iscfile), ' -isystem \\"', '\\"', '')
end

local function getlanguageflags(cfg)
local toolset = m.getToolset(cfg)
local compileas = toolset.shared and toolset.shared.compileas
if compileas then
return compileas[cfg.language] or ""
end
end

function m.generateCompileCommand(prj, cfg, node)
local toolset = m.getToolset(cfg)
local tool = path.iscfile(node.abspath) and 'cc' or 'cxx'
cfg.gccprefix = cfg.gccprefix or "" -- hack to have gcc.gettoolname return non-nil
local tool = toolset.gettoolname(cfg, tool) or tool
local system_flag = getsystemflags(tool, path.iscfile(node.abspath))
local language_flag = getlanguageflags(cfg) .. " "
return {
directory = prj.location,
file = node.abspath,
command = (tool .. system_flag .. " " .. language_flag .. table.concat(esc_table(m.getFileFlags(prj, cfg, node)), ' '))
}
end

function m.includeFile(prj, node, depth)
return path.iscppfile(node.abspath) or path.iscfile(node.abspath) or path.iscppheader(node.abspath)
end

function m.getProjectCommands(prj, cfg)
local tr = project.getsourcetree(prj)
local cmds = {}
p.tree.traverse(tr, {
onleaf = function(node, depth)
if m.includeFile(prj, node, depth) then
table.insert(cmds, m.generateCompileCommand(prj, cfg, node))
end
end
})
return cmds
end

local function get_architecture()
if jit then
return jit.arch
end

local handle = io.popen("uname -m 2>/dev/null")
if handle then
local arch = handle:read("*l")
handle:close()
if arch then return arch end
end

local arch = os.getenv("PROCESSOR_ARCHITECTURE")
if arch then
if arch == "AMD64" or arch == "IA64" then
return "x86_64"
end
return string.lower(arch)
end

return "x86_64"
end

function m.onWorkspace(wks)
local cfgCmds = {}
local prjLocs = {}
for prj in workspace.eachproject(wks) do
for cfg in project.eachconfig(prj) do
local cfgKey = string.format('%s', cfg.shortname)
if not cfgCmds[cfgKey] then
cfgCmds[cfgKey] = {}
end
cfgCmds[cfgKey] = table.join(cfgCmds[cfgKey], m.getProjectCommands(prj, cfg))
if not prjLocs[cfgKey] then
prjLocs[cfgKey] = {}
end
prjLocs[cfgKey].location = prj.location
end
end
for cfgKey,cmds in pairs(cfgCmds) do
local outfile = string.format('%s/compile_commands.json', cfgKey)
p.generate(wks, outfile, function(wks)
p.push('[')
for i = 1, #cmds do
local item = cmds[i]
p.push('{')
p.x('"directory": "%s",', item.directory)
p.x('"file": "%s",', item.file)
p.w('"command": "%s"', item.command)
if i ~= #cmds then
p.pop('},')
else
p.pop('}')
end
end
p.pop(']')
end)

if cfgKey == "release_" .. get_architecture() then
local source = path.join(prjLocs[cfgKey].location, outfile)
local destination = path.join(os.getcwd(), "compile_commands.json")
os.copyfile(source, destination)
end
end
end

newaction {
trigger = 'export-compile-commands',
description = 'Export compiler commands in JSON Compilation Database Format',
onWorkspace = m.onWorkspace,
toolset = "clang",
valid_kinds = { "ConsoleApp", "WindowedApp", "Makefile", "SharedLib", "StaticLib", "Utility" },
valid_languages = { "C", "C++" },
valid_tools = {
cc = { "gcc", "clang" }
}
}

return m
4 changes: 4 additions & 0 deletions premake4.lua
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,10 @@ function build_link_configuration( package_name, use_ee_icon )
end
end

if _OPTIONS["with-text-shaper"] then
defines { "EE_TEXT_SHAPER_ENABLED" }
end

set_ios_config()
set_apple_config()
build_arch_configuration()
Expand Down
6 changes: 6 additions & 0 deletions premake5.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "premake.export-compile-commands.export-compile-commands"

newoption { trigger = "with-openssl", description = "Enables OpenSSL support ( and disables mbedtls backend )." }
newoption { trigger = "with-dynamic-freetype", description = "Dynamic link against freetype." }
newoption { trigger = "with-static-eepp", description = "Force to build the demos and tests with eepp compiled statically" }
Expand Down Expand Up @@ -330,6 +332,10 @@ function build_link_configuration( package_name, use_ee_icon )
end
end

if _OPTIONS["with-text-shaper"] then
defines { "EE_TEXT_SHAPER_ENABLED" }
end

cppdialect "C++17"
set_ios_config()
set_apple_config()
Expand Down
15 changes: 8 additions & 7 deletions src/eepp/system/sys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,15 @@ static std::string GetWindowsArch() {
GetSystemInfo( &si );
}

if ( osvi.dwMajorVersion >= 6 ) {
if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ) {
arch = "x64";
} else if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ) {
arch = "x86";
}
} else {
if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ) {
arch = "x86_64";
} else if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ) {
arch = "x86";
} else if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64 ) {
arch = "arm64";
} else if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM ) {
arch = "arm";
}

return arch;
Expand Down

0 comments on commit 46b2a1b

Please sign in to comment.