comparison share/lua/5.2/luarocks/build/builtin.lua @ 1132:d137f631bad5

<GreyKnight> (cd luabuild/luarocks-2.0.12; make install)
author HackBot
date Fri, 14 Dec 2012 22:24:27 +0000
parents
children
comparison
equal deleted inserted replaced
1131:ff65dfb63263 1132:d137f631bad5
1
2 --- A builtin build system: back-end to provide a portable way of building C-based Lua modules.
3 module("luarocks.build.builtin", package.seeall)
4
5 local fs = require("luarocks.fs")
6 local path = require("luarocks.path")
7 local util = require("luarocks.util")
8 local cfg = require("luarocks.cfg")
9 local dir = require("luarocks.dir")
10
11 --- Run a command displaying its execution on standard output.
12 -- @return boolean: true if command succeeds (status code 0), false
13 -- otherwise.
14 local function execute(...)
15 io.stdout:write(table.concat({...}, " ").."\n")
16 return fs.execute(...)
17 end
18
19 --- Makes an RC file with an embedded Lua script, for building .exes on Windows
20 -- @return nil if could open files, error otherwise
21 local function make_rc(luafilename, rcfilename)
22 local rcfile = io.open(rcfilename, "w")
23 if not rcfile then
24 error("Could not open "..rcfilename.." for writing.")
25 end
26 rcfile:write("STRINGTABLE\r\nBEGIN\r\n")
27
28 local i = 1
29 for line in io.lines(luafilename) do
30 if not line:match("^#!") then
31 rcfile:write(i .. " \"")
32 line = line:gsub("\\", "\\\\"):gsub('"', '""'):gsub("[\r\n]+", "")
33 rcfile:write(line .. "\\r\\n\"\r\n")
34 i = i + 1
35 end
36 end
37
38 rcfile:write("END\r\n")
39
40 rcfile:close()
41 end
42
43 --- Driver function for the builtin build back-end.
44 -- @param rockspec table: the loaded rockspec.
45 -- @return boolean or (nil, string): true if no errors ocurred,
46 -- nil and an error message otherwise.
47 function run(rockspec)
48 assert(type(rockspec) == "table")
49 local compile_object, compile_library, compile_wrapper_binary
50
51 local build = rockspec.build
52 local variables = rockspec.variables
53
54 local function add_flags(extras, flag, flags)
55 if flags then
56 if type(flags) ~= "table" then
57 flags = { tostring(flags) }
58 end
59 util.variable_substitutions(flags, variables)
60 for _, v in ipairs(flags) do
61 table.insert(extras, flag:format(v))
62 end
63 end
64 end
65
66 if cfg.is_platform("mingw32") then
67 compile_object = function(object, source, defines, incdirs)
68 local extras = {}
69 add_flags(extras, "-D%s", defines)
70 add_flags(extras, "-I%s", incdirs)
71 return execute(variables.CC.." "..variables.CFLAGS, "-c", "-o", object, "-I"..variables.LUA_INCDIR, source, unpack(extras))
72 end
73 compile_library = function(library, objects, libraries, libdirs, name)
74 local extras = { unpack(objects) }
75 add_flags(extras, "-L%s", libdirs)
76 add_flags(extras, "%s.lib", libraries)
77 extras[#extras+1] = dir.path(variables.LUA_LIBDIR, variables.LUALIB)
78 extras[#extras+1] = "-l" .. (variables.MSVCRT or "msvcr80")
79 local ok = execute(variables.LD.." "..variables.LIBFLAG, "-o", library, unpack(extras))
80 return ok
81 end
82 compile_wrapper_binary = function(fullname, name)
83 local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\")
84 local basename = name:gsub("%.lua$", ""):gsub("/", "\\")
85 local rcname = basename..".rc"
86 local resname = basename..".o"
87 local wrapname = basename..".exe"
88 make_rc(fullname, fullbasename..".rc")
89 local ok = execute(variables.RC, "-o", resname, rcname)
90 if not ok then return ok end
91 ok = execute(variables.LD, "-o", wrapname, resname, variables.WRAPPER,
92 dir.path(variables.LUA_LIBDIR, variables.LUALIB), "-l" .. (variables.MSVCRT or "msvcr80"), "-luser32")
93 return ok, wrapname
94 end
95 elseif cfg.is_platform("win32") then
96 compile_object = function(object, source, defines, incdirs)
97 local extras = {}
98 add_flags(extras, "-D%s", defines)
99 add_flags(extras, "-I%s", incdirs)
100 return execute(variables.CC.." "..variables.CFLAGS, "-c", "-Fo"..object, "-I"..variables.LUA_INCDIR, source, unpack(extras))
101 end
102 compile_library = function(library, objects, libraries, libdirs, name)
103 local extras = { unpack(objects) }
104 add_flags(extras, "-libpath:%s", libdirs)
105 add_flags(extras, "%s.lib", libraries)
106 local basename = dir.base_name(library):gsub(".[^.]*$", "")
107 local deffile = basename .. ".def"
108 local def = io.open(dir.path(fs.current_dir(), deffile), "w+")
109 def:write("EXPORTS\n")
110 def:write("luaopen_"..name:gsub("%.", "_").."\n")
111 def:close()
112 local ok = execute(variables.LD, "-dll", "-def:"..deffile, "-out:"..library, dir.path(variables.LUA_LIBDIR, variables.LUALIB), unpack(extras))
113 local manifestfile = basename..".dll.manifest"
114 if ok and fs.exists(manifestfile) then
115 ok = execute(variables.MT, "-manifest", manifestfile, "-outputresource:"..basename..".dll;2")
116 end
117 return ok
118 end
119 compile_wrapper_binary = function(fullname, name)
120 local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\")
121 local basename = name:gsub("%.lua$", ""):gsub("/", "\\")
122 local rcname = basename..".rc"
123 local resname = basename..".res"
124 local wrapname = basename..".exe"
125 make_rc(fullname, fullbasename..".rc")
126 local ok = execute(variables.RC, "-r", "-fo"..resname, rcname)
127 if not ok then return ok end
128 ok = execute(variables.LD, "-out:"..wrapname, resname, variables.WRAPPER,
129 dir.path(variables.LUA_LIBDIR, variables.LUALIB), "user32.lib")
130 local manifestfile = wrapname..".manifest"
131 if ok and fs.exists(manifestfile) then
132 ok = execute(variables.MT, "-manifest", manifestfile, "-outputresource:"..wrapname..";1")
133 end
134 return ok, wrapname
135 end
136 else
137 compile_object = function(object, source, defines, incdirs)
138 local extras = {}
139 add_flags(extras, "-D%s", defines)
140 add_flags(extras, "-I%s", incdirs)
141 return execute(variables.CC.." "..variables.CFLAGS, "-I"..variables.LUA_INCDIR, "-c", source, "-o", object, unpack(extras))
142 end
143 compile_library = function (library, objects, libraries, libdirs)
144 local extras = { unpack(objects) }
145 add_flags(extras, "-L%s", libdirs)
146 if cfg.gcc_rpath then
147 add_flags(extras, "-Wl,-rpath,%s:", libdirs)
148 end
149 add_flags(extras, "-l%s", libraries)
150 if cfg.is_platform("cygwin") then
151 add_flags(extras, "-l%s", {"lua"})
152 end
153 return execute(variables.LD.." "..variables.LIBFLAG, "-o", library, "-L"..variables.LUA_LIBDIR, unpack(extras))
154 end
155 compile_wrapper_binary = function(fullname, name) return true, name end
156 end
157
158 local ok = true
159 local err = "Build error"
160 local built_modules = {}
161 local luadir = path.lua_dir(rockspec.name, rockspec.version)
162 local libdir = path.lib_dir(rockspec.name, rockspec.version)
163 local docdir = path.doc_dir(rockspec.name, rockspec.version)
164 -- On Windows, compiles an .exe for each Lua file in build.install.bin, and
165 -- replaces the filename with the .exe name. Strips the .lua extension if it exists,
166 -- otherwise just appends .exe to the name
167 if build.install and build.install.bin then
168 for i, name in ipairs(build.install.bin) do
169 local fullname = dir.path(fs.current_dir(), name)
170 local match = name:match("%.lua$")
171 local basename = name:gsub("%.lua$", "")
172 local file
173 if not match then
174 file = io.open(fullname)
175 end
176 if match or (file and file:read():match("#!.*lua.*")) then
177 ok, name = compile_wrapper_binary(fullname, name)
178 if ok then
179 build.install.bin[i] = name
180 else
181 if file then file:close() end
182 return nil, "Build error in wrapper binaries"
183 end
184 end
185 if file then file:close() end
186 end
187 end
188 for name, info in pairs(build.modules) do
189 local moddir = path.module_to_path(name)
190 if type(info) == "string" then
191 local ext = info:match(".([^.]+)$")
192 if ext == "lua" then
193 if info:match("init%.lua$") and not name:match("%.init$") then
194 moddir = path.module_to_path(name..".init")
195 end
196 local dest = dir.path(luadir, moddir)
197 built_modules[info] = dest
198 else
199 info = {info}
200 end
201 end
202 if type(info) == "table" then
203 local objects = {}
204 local sources = info.sources
205 if info[1] then sources = info end
206 if type(sources) == "string" then sources = {sources} end
207 for _, source in ipairs(sources) do
208 local object = source:gsub(".[^.]*$", "."..cfg.obj_extension)
209 if not object then
210 object = source.."."..cfg.obj_extension
211 end
212 ok = compile_object(object, source, info.defines, info.incdirs)
213 if not ok then
214 err = "Failed compiling object "..object
215 break
216 end
217 table.insert(objects, object)
218 end
219 if not ok then break end
220 local module_name = dir.path(moddir, name:match("([^.]*)$").."."..cfg.lib_extension):gsub("//", "/")
221 if moddir ~= "" then
222 fs.make_dir(moddir)
223 end
224 local dest = dir.path(libdir, moddir)
225 built_modules[module_name] = dest
226 ok = compile_library(module_name, objects, info.libraries, info.libdirs, name)
227 if not ok then
228 err = "Failed compiling module "..module_name
229 break
230 end
231 end
232 end
233 for name, dest in pairs(built_modules) do
234 fs.make_dir(dest)
235 ok = fs.copy(name, dest)
236 if not ok then
237 err = "Failed installing "..name.." in "..dest
238 break
239 end
240 end
241 if ok then
242 if fs.is_dir("lua") then
243 ok = fs.copy_contents("lua", luadir)
244 if not ok then err = "Failed copying contents of 'lua' directory." end
245 end
246 end
247 if ok then
248 return true
249 else
250 return nil, err
251 end
252 end