Add support for generating compile_commands.json (#39)
This commit is contained in:
25
.vscode/tasks.json
vendored
25
.vscode/tasks.json
vendored
@@ -95,7 +95,30 @@
|
|||||||
"osx": {
|
"osx": {
|
||||||
"command": "premake5.osx"
|
"command": "premake5.osx"
|
||||||
},
|
},
|
||||||
"group": "build"
|
"group": "build",
|
||||||
|
"dependsOn": ["Generate compile_commands.json"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Generate compile_commands.json",
|
||||||
|
"type": "process",
|
||||||
|
"command": "./premake5",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/build/"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"ecc"
|
||||||
|
],
|
||||||
|
"windows": {
|
||||||
|
"command": "./premake5.exe"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"command": "./premake5"
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"command": "premake5.osx"
|
||||||
|
},
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
29
build/ecc/LICENSE.md
Normal file
29
build/ecc/LICENSE.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2022, Matvey Bystrin
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
49
build/ecc/README.md
Normal file
49
build/ecc/README.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Export Compile Commands - ECC
|
||||||
|
Module implementing support for [JSON Compilation Database Format
|
||||||
|
Specification](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
|
||||||
|
|
||||||
|
This is an alternative to
|
||||||
|
[tarruda's](https://github.com/tarruda/premake-export-compile-commands) module,
|
||||||
|
which does one simple thing - generates one `compile_commands.json` file for
|
||||||
|
your project.
|
||||||
|
|
||||||
|
Tested with clangd-13.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
Premake 5.0.0 or later.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
Download premake-ecc and place it near your premake5.lua script. Then require it
|
||||||
|
from your premake script
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require "ecc/ecc"
|
||||||
|
```
|
||||||
|
|
||||||
|
After you simply can call:
|
||||||
|
|
||||||
|
```
|
||||||
|
premake5 ecc
|
||||||
|
```
|
||||||
|
|
||||||
|
Moldule will generate **one** `compile_commands.json` file near your main
|
||||||
|
premake script. During generation it will use the default config (the first one
|
||||||
|
you have specified in script). If you want to select specific config just pass
|
||||||
|
it's name with command line option:
|
||||||
|
|
||||||
|
```
|
||||||
|
premake5 --config=release ecc
|
||||||
|
```
|
||||||
|
|
||||||
|
Careful! `config` option case sensitive! If there is no config passed via
|
||||||
|
command line, module will choose the default one.
|
||||||
|
|
||||||
|
Note: if you want to embed this module into your premake build follow
|
||||||
|
the [manual](https://premake.github.io/docs/Embedding-Modules/)
|
||||||
|
|
||||||
|
## Future plans
|
||||||
|
- Add unit tests
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
- [export-compile-commands](https://github.com/tarruda/premake-export-compile-commands)
|
||||||
|
- [bear](https://github.com/rizsotto/Bear)
|
||||||
4
build/ecc/_manifest.lua
Normal file
4
build/ecc/_manifest.lua
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
return {
|
||||||
|
"_preload.lua",
|
||||||
|
"ecc.lua"
|
||||||
|
}
|
||||||
35
build/ecc/_preload.lua
Normal file
35
build/ecc/_preload.lua
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
local p = premake
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "config",
|
||||||
|
value = "CFG",
|
||||||
|
description = "Select config for export compile_commands.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
newaction {
|
||||||
|
trigger = "ecc",
|
||||||
|
shortname = "Export compile commands",
|
||||||
|
description = "Export compile_commands.json for language server",
|
||||||
|
toolset = "gcc",
|
||||||
|
|
||||||
|
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" },
|
||||||
|
valid_languages = { "C", "C++" },
|
||||||
|
valid_tools = {
|
||||||
|
cc = { "clang", "gcc" }
|
||||||
|
},
|
||||||
|
|
||||||
|
onStart = function()
|
||||||
|
p.indent(" ")
|
||||||
|
end,
|
||||||
|
|
||||||
|
execute = function()
|
||||||
|
local dir = {}
|
||||||
|
dir.location = _MAIN_SCRIPT_DIR
|
||||||
|
p.generate(dir, "compile_commands.json", p.modules.ecc.generateFile)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(cfg)
|
||||||
|
return (_ACTION == "ecc")
|
||||||
|
end
|
||||||
122
build/ecc/ecc.lua
Normal file
122
build/ecc/ecc.lua
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
-- Include module if it is not embedded
|
||||||
|
if premake.modules.ecc == nil then
|
||||||
|
include ( "_preload.lua" )
|
||||||
|
end
|
||||||
|
|
||||||
|
local p = premake
|
||||||
|
local project = p.project
|
||||||
|
|
||||||
|
p.modules.ecc = {}
|
||||||
|
local m = p.modules.ecc
|
||||||
|
|
||||||
|
m._VERSION = "1.0.1-alpha"
|
||||||
|
|
||||||
|
function m.generateFile()
|
||||||
|
p.push("[")
|
||||||
|
for wks in p.global.eachWorkspace() do
|
||||||
|
for prj in p.workspace.eachproject(wks) do
|
||||||
|
m.onProject(prj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p.pop("]")
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.onProject(prj)
|
||||||
|
if project.isc(prj) or project.iscpp(prj) then
|
||||||
|
local cfg = m.getConfig(prj)
|
||||||
|
local args = m.getArguments(prj, cfg)
|
||||||
|
local files = table.shallowcopy(prj._.files)
|
||||||
|
for i,node in ipairs(files) do
|
||||||
|
local output = cfg.objdir .. "/" .. node.objname .. ".o"
|
||||||
|
local obj = path.getrelative(prj.location, output)
|
||||||
|
p.push("{")
|
||||||
|
p.push("\"arguments\": [")
|
||||||
|
m.writeArgs(args, obj, node.relpath)
|
||||||
|
p.pop("],")
|
||||||
|
p.w("\"directory\": \"%s\",", prj.location)
|
||||||
|
p.w("\"file\": \"%s\",", node.abspath)
|
||||||
|
p.w("\"output\": \"%s\"", output)
|
||||||
|
p.pop("},")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.writeArgs(args, obj, src)
|
||||||
|
for _,arg in ipairs(args) do
|
||||||
|
-- Defines like the following will break JSON format, quotes need to be escaped
|
||||||
|
-- -DEXPORT_API=__attribute__((visibility("default")))
|
||||||
|
local escaped = arg:gsub("\"", "\\\"")
|
||||||
|
p.w("\"%s\",", escaped)
|
||||||
|
end
|
||||||
|
p.w("\"-c\",")
|
||||||
|
p.w("\"-o\",")
|
||||||
|
p.w("\"%s\",", obj)
|
||||||
|
p.w("\"%s\"", src)
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.getConfig(prj)
|
||||||
|
local ocfg = _OPTIONS.config
|
||||||
|
local cfg = {}
|
||||||
|
if ocfg and prj.configs[ocfg] then
|
||||||
|
cfg = prj.configs[ocfg]
|
||||||
|
else
|
||||||
|
cfg = m.defaultconfig(prj)
|
||||||
|
end
|
||||||
|
return cfg
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.getArguments(prj, cfg)
|
||||||
|
local toolset = m.getToolSet(cfg)
|
||||||
|
local args = {}
|
||||||
|
local tool = iif(project.iscpp(prj), "cxx", "cc")
|
||||||
|
local toolname = iif(cfg.prefix, toolset.gettoolname(cfg, tool), toolset.tools[tool])
|
||||||
|
args = table.join(args, toolname)
|
||||||
|
args = table.join(args, toolset.getcppflags(cfg)) -- Preprocessor
|
||||||
|
args = table.join(args, toolset.getdefines(cfg.defines))
|
||||||
|
args = table.join(args, toolset.getundefines(cfg.undefines))
|
||||||
|
args = table.join(args, toolset.getincludedirs(cfg, cfg.includedirs, cfg.sysincludedirs))
|
||||||
|
if project.iscpp(prj) then
|
||||||
|
args = table.join(args, toolset.getcxxflags(cfg))
|
||||||
|
else
|
||||||
|
args = table.join(args, toolset.getcflags(cfg))
|
||||||
|
end
|
||||||
|
args = table.join(args, cfg.buildoptions)
|
||||||
|
return args
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copied from gmake2 module
|
||||||
|
-- Return default toolset of given config or system default toolset
|
||||||
|
function m.getToolSet(cfg)
|
||||||
|
local default = iif(cfg.system == p.MACOSX, "clang", "gcc")
|
||||||
|
local toolset = p.tools[_OPTIONS.cc or cfg.toolset or default]
|
||||||
|
if not toolset then
|
||||||
|
error("Invalid toolset '" .. cfg.toolset .. "'")
|
||||||
|
end
|
||||||
|
return toolset
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copied from gmake2 module
|
||||||
|
function m.defaultconfig(target)
|
||||||
|
-- find the right configuration iterator function for this object
|
||||||
|
local eachconfig = iif(target.project, project.eachconfig, p.workspace.eachconfig)
|
||||||
|
local defaultconfig = nil
|
||||||
|
|
||||||
|
-- find the right default configuration platform, grab first configuration that matches
|
||||||
|
if target.defaultplatform then
|
||||||
|
for cfg in eachconfig(target) do
|
||||||
|
if cfg.platform == target.defaultplatform then
|
||||||
|
defaultconfig = cfg
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- grab the first configuration and write the block
|
||||||
|
if not defaultconfig then
|
||||||
|
local iter = eachconfig(target)
|
||||||
|
defaultconfig = iter()
|
||||||
|
end
|
||||||
|
|
||||||
|
return defaultconfig
|
||||||
|
end
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
-- Export Compile Commands module for clangd support
|
||||||
|
require "ecc/ecc"
|
||||||
|
|
||||||
newoption
|
newoption
|
||||||
{
|
{
|
||||||
trigger = "graphics",
|
trigger = "graphics",
|
||||||
|
|||||||
Reference in New Issue
Block a user