XMake: Add automatic header order fix

This commit is contained in:
Jérôme Leclercq 2021-10-28 09:53:43 +02:00
parent f491ee1e38
commit 66206868cd
4 changed files with 198 additions and 25 deletions

View File

@ -7,6 +7,8 @@
#ifndef NAZARA_OPENGLRENDERER_WRAPPER_COREFUNCTIONS_HPP
#define NAZARA_OPENGLRENDERER_WRAPPER_COREFUNCTIONS_HPP
// no include reordering
#define GL_GLES_PROTOTYPES 0
#include <GLES3/gl32.h>
#include <GLES2/gl2ext.h>

View File

@ -9,6 +9,8 @@
#undef WIN32_LEAN_AND_MEAN //< Redefined by wgl.h header (ty Khronos)
// no include reordering
#include <GLES3/gl3.h>
#include <GL/wgl.h>
#include <GL/wglext.h>

View File

@ -9,6 +9,8 @@
#undef WIN32_LEAN_AND_MEAN //< Redefined by wgl.h header (ty Khronos)
// no include reordering
#include <GLES3/gl3.h>
#include <GL/wgl.h>
#include <GL/wglext.h>

View File

@ -28,6 +28,42 @@ local function CompareLines(referenceLines, lines, firstLine, lineCount)
return true
end
local function ComputeHeaderFile(filePath)
local headerPath = filePath:gsub("[\\/]", "/")
headerPath = headerPath:sub(headerPath:find("Nazara/"), -1)
headerPath = headerPath:sub(1, headerPath:find("%..+$") - 1) .. ".hpp"
return headerPath
end
local systemHeaders = {
["fcntl.h"] = true,
["mstcpip"] = true,
["netdb.h"] = true,
["poll.h"] = true,
["process.h"] = true,
["pthread.h"] = true,
["unistd.h"] = true,
["windows.h"] = true,
["winsock2"] = true,
}
local function IsSystemHeader(header)
if systemHeaders[header] then
return true
end
if header:match("netinet/.*") then
return true
end
if header:match("sys/.*") then
return true
end
return false
end
on_run(function ()
import("core.base.option")
@ -281,10 +317,7 @@ on_run(function ()
for _, filePath in pairs(files) do
local lines = GetFile(filePath)
local headerPath = filePath:gsub("[\\/]", "/")
headerPath = headerPath:sub(headerPath:find("Nazara/"), -1)
headerPath = headerPath:sub(1, headerPath:find("%..+$") - 1) .. ".hpp"
local headerPath = ComputeHeaderFile(filePath)
if os.isfile("include/" .. headerPath) or os.isfile("src/" .. headerPath) then
local inclusions = {}
@ -296,7 +329,7 @@ on_run(function ()
break
end
local includeMode, includePath = lines[i]:match("^%s*#%s*include%s*([<\"])(.+)[>\"]")
local includeMode, includePath = lines[i]:match("^#include%s*([<\"])(.+)[>\"]")
if includeMode then
table.insert(inclusions, {
line = i,
@ -307,36 +340,24 @@ on_run(function ()
end
if #inclusions > 0 then
local increment = 0
-- Add corresponding header
local headerInclude
for i = 1, #inclusions do
if inclusions[i].path == headerPath then
headerInclude = i
if i ~= 1 then
print(filePath .. " doesn't include corresponding header first")
local currentInclusion = inclusions[i]
table.insert(fixes, {
File = filePath,
Func = function (lines)
table.remove(lines, currentInclusion.line)
local firstHeaderLine = inclusions[1].line
table.insert(lines, firstHeaderLine, "#include <" .. headerPath .. ">")
return lines
end
})
end
break
end
end
-- Check debug headers
local debugIncludeModule = moduleName ~= "Math" and moduleName or "Core"
local debugInclude
local debugIncludeOff
for i = 1, #inclusions do
local module, off = inclusions[i].path:match("Nazara/(.+)/Debug(O?f?f?).hpp")
local module, off = inclusions[i].path:match("^Nazara/(.+)/Debug(O?f?f?).hpp$")
if module then
if off == "Off" then
debugIncludeOff = i
@ -361,8 +382,7 @@ on_run(function ()
end
end
local increment = 0
-- Add header inclusion if it's missing
if not headerInclude then
print(filePath .. " is missing corresponding header inclusion")
@ -392,7 +412,7 @@ on_run(function ()
end
if path.extension(filePath) == ".inl" then
if not debugInclude then
if not debugIncludeOff then
print(filePath .. ": has missing DebugOff include")
table.insert(fixes, {
File = filePath,
@ -413,6 +433,153 @@ on_run(function ()
end
})
-- Reorder includes and remove duplicates
table.insert(checks, {
Name = "inclusion order",
Check = function (moduleName)
local files = table.join(
os.files("include/Nazara/" .. moduleName .. "/**.hpp"),
os.files("include/Nazara/" .. moduleName .. "/**.inl"),
os.files("src/Nazara/" .. moduleName .. "/**.hpp"),
os.files("src/Nazara/" .. moduleName .. "/**.inl"),
os.files("src/Nazara/" .. moduleName .. "/**.cpp")
)
local fixes = {}
for _, filePath in pairs(files) do
local lines = GetFile(filePath)
local headerPath = ComputeHeaderFile(filePath)
local inclusions = {}
-- Retrieve all inclusions from the first inclusion block
for i = 1, #lines do
if lines[i] == "// no include reordering" then
-- ignore file
inclusions = {}
break
end
local includeMode, includePath = lines[i]:match("^#include%s*([<\"])(.+)[>\"]")
if includeMode then
table.insert(inclusions, {
line = i,
mode = includeMode,
path = includePath
})
elseif #inclusions > 0 then
-- Stop when outside the inclusion block
break
end
end
local debugIncludeModule = moduleName ~= "Math" and moduleName or "Core"
local includeList = {}
local shouldReorder = false
for i = 1, #inclusions do
local order
if inclusions[i].path == headerPath or inclusions[i].path == "Nazara/Prerequisites.hpp" then
order = 0 -- own include comes first
elseif inclusions[i].path == "Nazara/" .. debugIncludeModule .. "/Debug.hpp" then
order = 5 -- debug include
elseif inclusions[i].path:match("^Nazara/") then
order = 1 -- engine includes
elseif IsSystemHeader(inclusions[i].path) then
order = 4 -- system includes
elseif inclusions[i].path:match(".+%.hp?p?") then
order = 2 -- thirdparty includes
else
order = 3 -- standard includes
end
table.insert(includeList, {
order = order,
path = inclusions[i].path,
content = lines[inclusions[i].line]
})
end
local function compareFunc(a, b)
if a.order == b.order then
local moduleA = a.path:match("^Nazara/(.-)/")
local moduleB = b.path:match("^Nazara/(.-)/")
if moduleA ~= moduleB then
return moduleA < moduleB
end
local _, folderCountA = a.path:gsub("/", "")
local _, folderCountB = b.path:gsub("/", "")
if folderCountA == folderCountB then
return a.path < b.path
else
return folderCountA < folderCountB
end
else
return a.order < b.order
end
end
local isOrdered = true
for i = 2, #includeList do
if includeList[i - 1].path == includeList[i].path then
-- duplicate found
print(filePath .. ": include list has duplicates")
isOrdered = false
break
end
if not compareFunc(includeList[i - 1], includeList[i]) then
print(filePath .. ": include list is not ordered")
isOrdered = false
break
end
end
if not isOrdered then
table.sort(includeList, compareFunc)
table.insert(fixes, {
File = filePath,
Func = function (lines)
-- Reorder includes
local newInclusions = {}
for i = 1, #inclusions do
lines[inclusions[i].line] = includeList[i].content
table.insert(newInclusions, {
content = includeList[i].content,
path = includeList[i].path,
line = inclusions[i].line
})
end
-- Remove duplicates
table.sort(newInclusions, function (a, b) return a.line > b.line end)
for i = 2, #newInclusions do
local a = newInclusions[i - 1]
local b = newInclusions[i]
if a.path == b.path then
if #a.content > #b.content then -- keep longest line (for comments)
table.remove(lines, b.line)
else
table.remove(lines, a.line)
end
end
end
return lines
end
})
end
end
return fixes
end
})
-- Check copyright date and format
table.insert(checks, {
Name = "copyright",