aboutsummaryrefslogtreecommitdiff
path: root/test/unit/preprocess.moon
diff options
context:
space:
mode:
authorNicolas Hillegeer <nicolas@hillegeer.com>2014-04-28 14:12:51 +0200
committerThiago de Arruda <tpadilha84@gmail.com>2014-04-28 16:17:25 -0300
commitd699ccfb0c3500becfec9b02c24dc858d54c5a6e (patch)
tree7178b1a7c0a1b90275f94a71851fbc106eae8d0a /test/unit/preprocess.moon
parent349f9da850fe46853663bff4ca199045a4678837 (diff)
downloadrneovim-d699ccfb0c3500becfec9b02c24dc858d54c5a6e.tar.gz
rneovim-d699ccfb0c3500becfec9b02c24dc858d54c5a6e.tar.bz2
rneovim-d699ccfb0c3500becfec9b02c24dc858d54c5a6e.zip
test: fix the cimport method
This commit will hopefully allow the cimport method to be used just as one would use #inclue <header.h> in C. It follows the following method: 1. create a pseudoheader file that #include's all the requested header files 2. runs the pseudoheader through the C preprocessor (it will try various compilers if available on the system). 3. runs the preprocessed file through a C formatter, which attempts to group statements on one line. For example, a struct definition that was formerly on several lines will take just one line after formatting. This is done so that unique declarations can be detected. Duplicates are thus easy to remove. 4. remove lines that are too complex for the LuaJIT C parser (such as: Objective-C block syntax, crazy enums defined on linux, ...) 5. remove duplicate declarations 6. pass result to ffi.cdef
Diffstat (limited to 'test/unit/preprocess.moon')
-rw-r--r--test/unit/preprocess.moon155
1 files changed, 155 insertions, 0 deletions
diff --git a/test/unit/preprocess.moon b/test/unit/preprocess.moon
new file mode 100644
index 0000000000..88580476b2
--- /dev/null
+++ b/test/unit/preprocess.moon
@@ -0,0 +1,155 @@
+-- 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 acording 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_GNU_SOURCE'
+ }
+
+ 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(...)
+}