mirror of
https://github.com/neovim/neovim.git
synced 2025-12-19 12:55:32 +00:00
unittest: Allow multiple indirect includes
Works by saving all preprocessor defines and reusing them on each run. This also saves NVIM_HEADER_H defines. Saving other defines is needed for defines like `Map(foo, bar)` which are sometimes used to declare types or functions. Saving types or function declarations is not needed because they are recorded as luajit state. Fixes #5857
This commit is contained in:
@@ -21,6 +21,9 @@ local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N',
|
|||||||
|
|
||||||
local mpack = require('mpack')
|
local mpack = require('mpack')
|
||||||
|
|
||||||
|
local tmpname = global_helpers.tmpname
|
||||||
|
local uname = global_helpers.uname
|
||||||
|
|
||||||
-- Formulate a path to the directory containing nvim. We use this to
|
-- Formulate a path to the directory containing nvim. We use this to
|
||||||
-- help run test executables. It helps to keep the tests working, even
|
-- help run test executables. It helps to keep the tests working, even
|
||||||
-- when the build is not in the default location.
|
-- when the build is not in the default location.
|
||||||
@@ -334,44 +337,6 @@ local function write_file(name, text, dont_dedent)
|
|||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Tries to get platform name from $SYSTEM_NAME, uname; fallback is "Windows".
|
|
||||||
local uname = (function()
|
|
||||||
local platform = nil
|
|
||||||
return (function()
|
|
||||||
if platform then
|
|
||||||
return platform
|
|
||||||
end
|
|
||||||
|
|
||||||
platform = os.getenv("SYSTEM_NAME")
|
|
||||||
if platform then
|
|
||||||
return platform
|
|
||||||
end
|
|
||||||
|
|
||||||
local status, f = pcall(io.popen, "uname -s")
|
|
||||||
if status then
|
|
||||||
platform = f:read("*l")
|
|
||||||
else
|
|
||||||
platform = 'Windows'
|
|
||||||
end
|
|
||||||
return platform
|
|
||||||
end)
|
|
||||||
end)()
|
|
||||||
|
|
||||||
local function tmpname()
|
|
||||||
local fname = os.tmpname()
|
|
||||||
if uname() == 'Windows' and fname:sub(1, 2) == '\\s' then
|
|
||||||
-- In Windows tmpname() returns a filename starting with
|
|
||||||
-- special sequence \s, prepend $TEMP path
|
|
||||||
local tmpdir = os.getenv('TEMP')
|
|
||||||
return tmpdir..fname
|
|
||||||
elseif fname:match('^/tmp') and uname() == 'Darwin' then
|
|
||||||
-- In OS X /tmp links to /private/tmp
|
|
||||||
return '/private'..fname
|
|
||||||
else
|
|
||||||
return fname
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function source(code)
|
local function source(code)
|
||||||
local fname = tmpname()
|
local fname = tmpname()
|
||||||
write_file(fname, code)
|
write_file(fname, code)
|
||||||
|
|||||||
@@ -52,9 +52,49 @@ local function check_logs()
|
|||||||
assert(0 == runtime_errors)
|
assert(0 == runtime_errors)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Tries to get platform name from $SYSTEM_NAME, uname; fallback is "Windows".
|
||||||
|
local uname = (function()
|
||||||
|
local platform = nil
|
||||||
|
return (function()
|
||||||
|
if platform then
|
||||||
|
return platform
|
||||||
|
end
|
||||||
|
|
||||||
|
platform = os.getenv("SYSTEM_NAME")
|
||||||
|
if platform then
|
||||||
|
return platform
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, f = pcall(io.popen, "uname -s")
|
||||||
|
if status then
|
||||||
|
platform = f:read("*l")
|
||||||
|
else
|
||||||
|
platform = 'Windows'
|
||||||
|
end
|
||||||
|
return platform
|
||||||
|
end)
|
||||||
|
end)()
|
||||||
|
|
||||||
|
local function tmpname()
|
||||||
|
local fname = os.tmpname()
|
||||||
|
if uname() == 'Windows' and fname:sub(1, 2) == '\\s' then
|
||||||
|
-- In Windows tmpname() returns a filename starting with
|
||||||
|
-- special sequence \s, prepend $TEMP path
|
||||||
|
local tmpdir = os.getenv('TEMP')
|
||||||
|
return tmpdir..fname
|
||||||
|
elseif fname:match('^/tmp') and uname() == 'Darwin' then
|
||||||
|
-- In OS X /tmp links to /private/tmp
|
||||||
|
return '/private'..fname
|
||||||
|
else
|
||||||
|
return fname
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
eq = eq,
|
eq = eq,
|
||||||
neq = neq,
|
neq = neq,
|
||||||
ok = ok,
|
ok = ok,
|
||||||
check_logs = check_logs,
|
check_logs = check_logs,
|
||||||
|
uname = uname,
|
||||||
|
tmpname = tmpname,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,12 +219,10 @@ local function standalone(...) -- luacheck: ignore
|
|||||||
Preprocess.add_to_include_path('./../../build/include')
|
Preprocess.add_to_include_path('./../../build/include')
|
||||||
Preprocess.add_to_include_path('./../../.deps/usr/include')
|
Preprocess.add_to_include_path('./../../.deps/usr/include')
|
||||||
|
|
||||||
local input = Preprocess.preprocess_stream(arg[1])
|
local raw = Preprocess.preprocess(arg[1])
|
||||||
local raw = input:read('*all')
|
|
||||||
input:close()
|
|
||||||
|
|
||||||
if raw == nil then
|
if raw == nil then
|
||||||
print("ERROR: Preprocess.preprocess_stream():read() returned empty")
|
print("ERROR: Preprocess.preprocess() returned empty")
|
||||||
end
|
end
|
||||||
|
|
||||||
local formatted
|
local formatted
|
||||||
|
|||||||
@@ -68,14 +68,12 @@ local function cimport(...)
|
|||||||
|
|
||||||
local body = nil
|
local body = nil
|
||||||
for _ = 1, 10 do
|
for _ = 1, 10 do
|
||||||
local stream = Preprocess.preprocess_stream(unpack(paths))
|
body = Preprocess.preprocess(unpack(paths))
|
||||||
body = stream:read("*a")
|
|
||||||
stream:close()
|
|
||||||
if body ~= nil then break end
|
if body ~= nil then break end
|
||||||
end
|
end
|
||||||
|
|
||||||
if body == nil then
|
if body == nil then
|
||||||
print("ERROR: helpers.lua: Preprocess.preprocess_stream():read() returned empty")
|
print("ERROR: helpers.lua: Preprocess.preprocess() returned empty")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- format it (so that the lines are "unique" statements), also filter out
|
-- format it (so that the lines are "unique" statements), also filter out
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
-- helps managing loading different headers into the LuaJIT ffi. Untested on
|
-- helps managing loading different headers into the LuaJIT ffi. Untested on
|
||||||
-- windows, will probably need quite a bit of adjustment to run there.
|
-- windows, will probably need quite a bit of adjustment to run there.
|
||||||
|
|
||||||
|
local global_helpers = require('test.helpers')
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
|
|
||||||
|
local tmpname = global_helpers.tmpname
|
||||||
|
|
||||||
local ccs = {}
|
local ccs = {}
|
||||||
|
|
||||||
local env_cc = os.getenv("CC")
|
local env_cc = os.getenv("CC")
|
||||||
@@ -61,12 +65,12 @@ end
|
|||||||
-- will produce a string that represents a meta C header file that includes
|
-- will produce a string that represents a meta C header file that includes
|
||||||
-- all the passed in headers. I.e.:
|
-- all the passed in headers. I.e.:
|
||||||
--
|
--
|
||||||
-- headerize({"stdio.h", "math.h", true}
|
-- headerize({"stdio.h", "math.h"}, true)
|
||||||
-- produces:
|
-- produces:
|
||||||
-- #include <stdio.h>
|
-- #include <stdio.h>
|
||||||
-- #include <math.h>
|
-- #include <math.h>
|
||||||
--
|
--
|
||||||
-- headerize({"vim.h", "memory.h", false}
|
-- headerize({"vim.h", "memory.h"}, false)
|
||||||
-- produces:
|
-- produces:
|
||||||
-- #include "vim.h"
|
-- #include "vim.h"
|
||||||
-- #include "memory.h"
|
-- #include "memory.h"
|
||||||
@@ -79,8 +83,7 @@ local function headerize(headers, global)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local formatted = {}
|
local formatted = {}
|
||||||
for i = 1, #headers do
|
for i, hdr in ipairs(headers) do
|
||||||
local hdr = headers[i]
|
|
||||||
formatted[#formatted + 1] = "#include " ..
|
formatted[#formatted + 1] = "#include " ..
|
||||||
tostring(pre) ..
|
tostring(pre) ..
|
||||||
tostring(hdr) ..
|
tostring(hdr) ..
|
||||||
@@ -111,7 +114,8 @@ local Gcc = {
|
|||||||
'-D "_Nullable="',
|
'-D "_Nullable="',
|
||||||
'-D "_Nonnull="',
|
'-D "_Nonnull="',
|
||||||
'-U__BLOCKS__',
|
'-U__BLOCKS__',
|
||||||
}
|
},
|
||||||
|
added_header_defines = '',
|
||||||
}
|
}
|
||||||
|
|
||||||
function Gcc:new(obj)
|
function Gcc:new(obj)
|
||||||
@@ -145,21 +149,40 @@ end
|
|||||||
|
|
||||||
-- returns a stream representing a preprocessed form of the passed-in headers.
|
-- returns a stream representing a preprocessed form of the passed-in headers.
|
||||||
-- Don't forget to close the stream by calling the close() method on it.
|
-- Don't forget to close the stream by calling the close() method on it.
|
||||||
function Gcc:preprocess_stream(...)
|
function Gcc:preprocess(...)
|
||||||
-- create pseudo-header
|
-- create pseudo-header
|
||||||
local pseudoheader = headerize({...}, false)
|
local pseudoheader = headerize({...}, false)
|
||||||
|
local pseudoheader_fname = 'tmp_pseudoheader.h'
|
||||||
|
local pseudoheader_file = io.open(pseudoheader_fname, 'w')
|
||||||
|
pseudoheader_file:write(self.added_header_defines)
|
||||||
|
pseudoheader_file:write("\n")
|
||||||
|
pseudoheader_file:write(pseudoheader)
|
||||||
|
pseudoheader_file:flush()
|
||||||
|
pseudoheader_file:close()
|
||||||
local defines = table.concat(self.preprocessor_extra_flags, ' ')
|
local defines = table.concat(self.preprocessor_extra_flags, ' ')
|
||||||
local cmd = ("echo $hdr | " ..
|
local cmd = ("echo $hdr | " ..
|
||||||
tostring(self.path) ..
|
tostring(self.path) ..
|
||||||
" " ..
|
" " ..
|
||||||
tostring(defines) ..
|
tostring(defines) ..
|
||||||
" -std=c99 -P -E -"):gsub('$hdr', shell_quote(pseudoheader))
|
" -std=c99 -P -E " .. shell_quote(pseudoheader_fname))
|
||||||
|
local def_cmd = ("echo $hdr | " ..
|
||||||
|
tostring(self.path) ..
|
||||||
|
" " ..
|
||||||
|
tostring(defines) ..
|
||||||
|
" -std=c99 -dM -E " .. shell_quote(pseudoheader_fname))
|
||||||
|
local def_stream = io.popen(def_cmd)
|
||||||
|
self.added_header_defines = def_stream:read('*a')
|
||||||
|
def_stream:close()
|
||||||
-- lfs = require("lfs")
|
-- lfs = require("lfs")
|
||||||
-- print("CWD: #{lfs.currentdir!}")
|
-- print("CWD: #{lfs.currentdir!}")
|
||||||
-- print("CMD: #{cmd}")
|
-- print("CMD: #{cmd}")
|
||||||
-- io.stderr\write("CWD: #{lfs.currentdir!}\n")
|
-- io.stderr\write("CWD: #{lfs.currentdir!}\n")
|
||||||
-- io.stderr\write("CMD: #{cmd}\n")
|
-- io.stderr\write("CMD: #{cmd}\n")
|
||||||
return io.popen(cmd)
|
local stream = io.popen(cmd)
|
||||||
|
local ret = stream:read('*a')
|
||||||
|
stream:close()
|
||||||
|
os.remove(pseudoheader_fname)
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
local Clang = Gcc:new()
|
local Clang = Gcc:new()
|
||||||
@@ -197,8 +220,8 @@ return {
|
|||||||
includes = function(hdr)
|
includes = function(hdr)
|
||||||
return cc:dependencies(hdr)
|
return cc:dependencies(hdr)
|
||||||
end,
|
end,
|
||||||
preprocess_stream = function(...)
|
preprocess = function(...)
|
||||||
return cc:preprocess_stream(...)
|
return cc:preprocess(...)
|
||||||
end,
|
end,
|
||||||
add_to_include_path = function(...)
|
add_to_include_path = function(...)
|
||||||
return cc:add_to_include_path(...)
|
return cc:add_to_include_path(...)
|
||||||
|
|||||||
Reference in New Issue
Block a user