diff options
-rw-r--r-- | test/unit/preprocess.lua | 198 | ||||
-rw-r--r-- | test/unit/preprocess.moon | 158 |
2 files changed, 198 insertions, 158 deletions
diff --git a/test/unit/preprocess.lua b/test/unit/preprocess.lua new file mode 100644 index 0000000000..2405270328 --- /dev/null +++ b/test/unit/preprocess.lua @@ -0,0 +1,198 @@ +-- helps managing loading different headers into the LuaJIT ffi. Untested on +-- windows, will probably need quite a bit of adjustment to run there. + +local ffi = require("ffi") + +local ccs = {} + +local env_cc = os.getenv("CC") +if env_cc then + table.insert(ccs, {path = "/usr/bin/env " .. tostring(env_cc), type = "gcc"}) +end + +if ffi.os == "Windows" then + table.insert(ccs, {path = "cl", type = "msvc"}) +end + +table.insert(ccs, {path = "/usr/bin/env cc", type = "gcc"}) +table.insert(ccs, {path = "/usr/bin/env gcc", type = "gcc"}) +table.insert(ccs, {path = "/usr/bin/env gcc-4.9", type = "gcc"}) +table.insert(ccs, {path = "/usr/bin/env gcc-4.8", type = "gcc"}) +table.insert(ccs, {path = "/usr/bin/env gcc-4.7", type = "gcc"}) +table.insert(ccs, {path = "/usr/bin/env clang", type = "clang"}) +table.insert(ccs, {path = "/usr/bin/env icc", type = "gcc"}) + +local quote_me = '[^%w%+%-%=%@%_%/]' -- complement (needn't quote) +function shell_quote(str) + if string.find(str, quote_me) or str == '' then + return "'" .. string.gsub(str, "'", [['"'"']]) .. "'" + else + return str + end +end + +-- parse Makefile format dependencies into a Lua table +function parse_make_deps(deps) + -- remove line breaks and line concatenators + deps = deps:gsub("\n", ""):gsub("\\", "") + -- remove the Makefile "target:" element + deps = deps:gsub(".+:", "") + -- remove redundant spaces + deps = deps:gsub(" +", " ") + + -- split according to token (space in this case) + local headers = {} + for token in deps:gmatch("[^%s]+") do + -- headers[token] = true + headers[#headers + 1] = token + end + + -- resolve path redirections (..) to normalize all paths + for i, v in ipairs(headers) do + -- double dots (..) + headers[i] = v:gsub("/[^/%s]+/%.%.", "") + -- single dot (.) + headers[i] = v:gsub("%./", "") + end + + return headers +end + +-- will produce a string that represents a meta C header file that includes +-- all the passed in headers. I.e.: +-- +-- headerize({"stdio.h", "math.h", true} +-- produces: +-- #include <stdio.h> +-- #include <math.h> +-- +-- headerize({"vim.h", "memory.h", false} +-- produces: +-- #include "vim.h" +-- #include "memory.h" +function headerize(headers, global) + local pre = '"' + local post = pre + if global then + pre = "<" + post = ">" + end + + local formatted = {} + for i = 1, #headers do + local hdr = headers[i] + formatted[#formatted + 1] = "#include " .. + tostring(pre) .. + tostring(hdr) .. + tostring(post) + end + + return table.concat(formatted, "\n") +end + +local Gcc = { + -- preprocessor flags that will hopefully make the compiler produce C + -- declarations that the LuaJIT ffi understands. + preprocessor_extra_flags = { + '-D "aligned(ARGS)="', + '-D "__attribute__(ARGS)="', + '-D "__asm(ARGS)="', + '-D "__asm__(ARGS)="', + '-D "__inline__="', + '-D "EXTERN=extern"', + '-D "INIT(...)="', + '-D_GNU_SOURCE', + '-DINCLUDE_GENERATED_DECLARATIONS' + } +} + +function Gcc:new(obj) + obj = obj or {} + setmetatable(obj, self) + self.__index = self + return obj +end + +function Gcc:add_to_include_path(...) + local paths = {...} + for i = 1, #paths do + local path = paths[i] + local directive = '-I ' .. '"' .. path .. '"' + local ef = self.preprocessor_extra_flags + ef[#ef + 1] = directive + end +end + +-- returns a list of the headers files upon which this file relies +function Gcc:dependencies(hdr) + local out = io.popen(tostring(self.path) .. " -M " .. tostring(hdr) .. " 2>&1") + local deps = out:read("*a") + out:close() + if deps then + return parse_make_deps(deps) + else + return nil + end +end + +-- 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. +function Gcc:preprocess_stream(...) + -- create pseudo-header + local pseudoheader = headerize({...}, false) + local defines = table.concat(self.preprocessor_extra_flags, ' ') + local cmd = ("echo $hdr | " .. + tostring(self.path) .. + " " .. + tostring(defines) .. + " -std=c99 -P -E -"):gsub('$hdr', shell_quote(pseudoheader)) + -- lfs = require("lfs") + -- print("CWD: #{lfs.currentdir!}") + -- print("CMD: #{cmd}") + -- io.stderr\write("CWD: #{lfs.currentdir!}\n") + -- io.stderr\write("CMD: #{cmd}\n") + return io.popen(cmd) +end + +local Clang = Gcc:new() +local Msvc = Gcc:new() + +local type_to_class = { + ["gcc"] = Gcc, + ["clang"] = Clang, + ["msvc"] = Msvc +} + +-- find the best cc. If os.exec causes problems on windows (like popping up +-- a console window) we might consider using something like this: +-- http://scite-ru.googlecode.com/svn/trunk/pack/tools/LuaLib/shell.html#exec +function find_best_cc(ccs) + for _, meta in pairs(ccs) do + local version = io.popen(tostring(meta.path) .. " -v 2>&1") + version:close() + if version then + return type_to_class[meta.type]:new({path = meta.path}) + end + end + return nil +end + +-- find the best cc. If os.exec causes problems on windows (like popping up +-- a console window) we might consider using something like this: +-- http://scite-ru.googlecode.com/svn/trunk/pack/tools/LuaLib/shell.html#exec +local cc = nil +if cc == nil then + cc = find_best_cc(ccs) +end + +return { + includes = function(hdr) + return cc:dependencies(hdr) + end, + preprocess_stream = function(...) + return cc:preprocess_stream(...) + end, + add_to_include_path = function(...) + return cc:add_to_include_path(...) + end +} diff --git a/test/unit/preprocess.moon b/test/unit/preprocess.moon deleted file mode 100644 index cb734da2f7..0000000000 --- a/test/unit/preprocess.moon +++ /dev/null @@ -1,158 +0,0 @@ --- helps managing loading different headers into the LuaJIT ffi. Untested on --- windows, will probably need quite a bit of adjustment to run there. - -ffi = require("ffi") - -ccs = {} - -env_cc = os.getenv("CC") -if env_cc - table.insert(ccs, {path: "/usr/bin/env #{env_cc}", type: "gcc"}) - -if ffi.os == "Windows" - table.insert(ccs, {path: "cl", type: "msvc"}) - -table.insert(ccs, {path: "/usr/bin/env cc", type: "gcc"}) -table.insert(ccs, {path: "/usr/bin/env gcc", type: "gcc"}) -table.insert(ccs, {path: "/usr/bin/env gcc-4.9", type: "gcc"}) -table.insert(ccs, {path: "/usr/bin/env gcc-4.8", type: "gcc"}) -table.insert(ccs, {path: "/usr/bin/env gcc-4.7", type: "gcc"}) -table.insert(ccs, {path: "/usr/bin/env clang", type: "clang"}) -table.insert(ccs, {path: "/usr/bin/env icc", type: "gcc"}) - -quote_me = '[^%w%+%-%=%@%_%/]' -- complement (needn't quote) -shell_quote = (str) -> - if string.find(str, quote_me) or str == '' then - "'" .. string.gsub(str, "'", [['"'"']]) .. "'" - else - str - --- parse Makefile format dependencies into a Lua table -parse_make_deps = (deps) -> - -- remove line breaks and line concatenators - deps = deps\gsub("\n", "")\gsub("\\", "") - - -- remove the Makefile "target:" element - deps = deps\gsub(".+:", "") - - -- remove redundant spaces - deps = deps\gsub(" +", " ") - - -- split according to token (space in this case) - headers = {} - for token in deps\gmatch("[^%s]+") - -- headers[token] = true - headers[#headers + 1] = token - - -- resolve path redirections (..) to normalize all paths - for i, v in ipairs(headers) - -- double dots (..) - headers[i] = v\gsub("/[^/%s]+/%.%.", "") - - -- single dot (.) - headers[i] = v\gsub("%./", "") - - headers - --- will produce a string that represents a meta C header file that includes --- all the passed in headers. I.e.: --- --- headerize({"stdio.h", "math.h", true} --- produces: --- #include <stdio.h> --- #include <math.h> --- --- headerize({"vim.h", "memory.h", false} --- produces: --- #include "vim.h" --- #include "memory.h" -headerize = (headers, global) -> - pre = '"' - post = pre - if global - pre = "<" - post = ">" - - formatted = ["#include #{pre}#{hdr}#{post}" for hdr in *headers] - table.concat(formatted, "\n") - -class Gcc - -- preprocessor flags that will hopefully make the compiler produce C - -- declarations that the LuaJIT ffi understands. - @@preprocessor_extra_flags = { - '-D "aligned(ARGS)="', - '-D "__attribute__(ARGS)="', - '-D "__asm(ARGS)="', - '-D "__asm__(ARGS)="', - '-D "__inline__="', - '-D "EXTERN=extern"', - '-D "INIT(...)="', - '-D_GNU_SOURCE', - '-DINCLUDE_GENERATED_DECLARATIONS' - } - - new: (path) => - @path = path - - add_to_include_path: (...) => - paths = {...} - for path in *paths - directive = '-I ' .. '"' .. path .. '"' - @@preprocessor_extra_flags[#@@preprocessor_extra_flags + 1] = directive - - -- returns a list of the headers files upon which this file relies - dependencies: (hdr) => - out = io.popen("#{@path} -M #{hdr} 2>&1") - deps = out\read("*a") - out\close! - - if deps - parse_make_deps(deps) - else - nil - - -- 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. - preprocess_stream: (...) => - paths = {...} - -- create pseudo-header - pseudoheader = headerize(paths, false) - defines = table.concat(@@preprocessor_extra_flags, ' ') - cmd = ("echo $hdr | #{@path} #{defines} -std=c99 -P -E -")\gsub('$hdr', shell_quote(pseudoheader)) - -- lfs = require("lfs") - -- print("CWD: #{lfs.currentdir!}") - -- print("CMD: #{cmd}") - -- io.stderr\write("CWD: #{lfs.currentdir!}\n") - -- io.stderr\write("CMD: #{cmd}\n") - io.popen(cmd) - -class Clang extends Gcc -class Msvc extends Gcc - -type_to_class = { - "gcc": Gcc, - "clang": Clang, - "msvc": Msvc -} - -find_best_cc = (ccs) -> - for _, meta in pairs(ccs) - version = io.popen("#{meta.path} -v 2>&1") - version\close! - if version - return type_to_class[meta.type](meta.path) - nil - --- find the best cc. If os.exec causes problems on windows (like popping up --- a console window) we might consider using something like this: --- http://scite-ru.googlecode.com/svn/trunk/pack/tools/LuaLib/shell.html#exec -cc = nil -if cc == nil - cc = find_best_cc(ccs) - -return { - includes: (hdr) -> cc\dependencies(hdr) - preprocess_stream: (...) -> cc\preprocess_stream(...) - add_to_include_path: (...) -> cc\add_to_include_path(...) -} |