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:
ZyX
2017-01-03 08:46:44 +03:00
parent efe1476d42
commit 410d18ef5c
5 changed files with 80 additions and 56 deletions

View File

@@ -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)

View File

@@ -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,
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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(...)