summaryrefslogtreecommitdiff
path: root/xmake/plugins/project/make/makefile.lua
diff options
context:
space:
mode:
authorruki <[email protected]>2019-02-13 22:37:00 +0800
committerruki <[email protected]>2019-02-13 09:42:01 +0800
commitb0ab905e2ae98b4ebb66eea9e0a635fc834019be (patch)
tree54be72a83658d7e94417924826523f32e15c54c7 /xmake/plugins/project/make/makefile.lua
parente6b1a84a210d20f69f9987054c21ab64157f77d9 (diff)
add cmakelists plugin stub
Diffstat (limited to 'xmake/plugins/project/make/makefile.lua')
-rw-r--r--xmake/plugins/project/make/makefile.lua532
1 files changed, 532 insertions, 0 deletions
diff --git a/xmake/plugins/project/make/makefile.lua b/xmake/plugins/project/make/makefile.lua
new file mode 100644
index 000000000..9e2f2a51d
--- /dev/null
+++ b/xmake/plugins/project/make/makefile.lua
@@ -0,0 +1,532 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2019, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file makefile.lua
+--
+
+-- imports
+import("core.tool.compiler")
+import("core.project.project")
+import("core.language.language")
+import("core.platform.platform")
+
+-- get log makefile
+function _logfile()
+
+ -- get it
+ return vformat("$(buildir)/.build.log")
+end
+
+-- mkdir directory
+function _mkdir(makefile, dir)
+
+ if is_plat("windows") then
+ makefile:print("\t-@mkdir %s > NUL 2>&1", dir)
+ else
+ makefile:print("\t@mkdir -p %s", dir)
+ end
+end
+
+-- copy file
+function _cp(makefile, sourcefile, targetfile)
+
+ -- copy file
+ if is_plat("windows") then
+ makefile:print("\t@copy /Y %s %s > NUL 2>&1", sourcefile, targetfile)
+ else
+ makefile:print("\t@cp %s %s", sourcefile, targetfile)
+ end
+end
+
+-- try to remove the given file or directory
+function _tryrm(makefile, filedir)
+
+ -- remove it
+ if is_plat("windows") then
+ if os.isdir(filedir) then
+ makefile:print("\t@rmdir /S /Q %s > NUL 2>&1", filedir)
+ elseif os.isfile(filedir) then
+ makefile:print("\t@del /F /Q %s > NUL 2>&1", filedir)
+ end
+ else
+ if os.isdir(filedir) then
+ makefile:print("\t@rm -rf %s", filedir)
+ elseif os.isfile(filedir) then
+ makefile:print("\t@rm -f %s", filedir)
+ end
+ end
+end
+
+-- remove the given files or directories
+function _remove(makefile, filedirs)
+ for _, filedir in ipairs(filedirs) do
+ _tryrm(makefile, filedir)
+ end
+end
+
+-- make common flags
+function _make_common_flags(target, sourcekind, sourcebatch)
+
+ -- make source flags
+ local sourceflags = {}
+ local flags_stats = {}
+ local files_count = 0
+ local first_flags = nil
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+
+ -- make compiler flags
+ local flags = compiler.compflags(sourcefile, {target = target, sourcekind = sourcekind})
+ for _, flag in ipairs(flags) do
+ flags_stats[flag] = (flags_stats[flag] or 0) + 1
+ end
+
+ -- update files count
+ files_count = files_count + 1
+
+ -- save first flags
+ if first_flags == nil then
+ first_flags = flags
+ end
+
+ -- save source flags
+ sourceflags[sourcefile] = flags
+ end
+
+ -- make common flags
+ local commonflags = {}
+ for _, flag in ipairs(first_flags) do
+ if flags_stats[flag] == files_count then
+ table.insert(commonflags, flag)
+ end
+ end
+
+ -- remove common flags from source flags
+ local sourceflags_ = {}
+ for sourcefile, flags in pairs(sourceflags) do
+ local otherflags = {}
+ for _, flag in ipairs(flags) do
+ if flags_stats[flag] ~= files_count then
+ table.insert(otherflags, flag)
+ end
+ end
+ sourceflags_[sourcefile] = otherflags
+ end
+
+ -- ok?
+ return commonflags, sourceflags_
+end
+
+-- make the object for the *.[o|obj] source file
+function _make_object_for_object(makefile, target, sourcefile, objectfile)
+
+ -- make command
+ local cmd = format("xmake l cp %s %s", sourcefile, objectfile)
+
+ -- make head
+ makefile:printf("%s:", objectfile)
+
+ -- make dependence
+ makefile:print(" %s", sourcefile)
+
+ -- make body
+ makefile:print("\t@echo inserting.$(mode) %s", sourcefile)
+ makefile:print("\t@%s", cmd)
+
+ -- make tail
+ makefile:print("")
+
+end
+
+-- make the object for the *.[a|lib] source file
+function _make_object_for_static(makefile, target, sourcefile, objectfile)
+
+ -- not supported
+ raise("source file: %s not supported!", sourcefile)
+end
+
+-- make the object
+function _make_object(makefile, target, sourcefile, objectfile, sourceflags)
+
+ -- get the source file kind
+ local sourcekind = language.sourcekind_of(sourcefile)
+
+ -- make the object for the *.o/obj source makefile
+ if sourcekind == "obj" then
+ return _make_object_for_object(makefile, target, sourcefile, objectfile)
+ -- make the object for the *.[a|lib] source file
+ elseif sourcekind == "lib" then
+ return _make_object_for_static(makefile, target, sourcefile, objectfile)
+ end
+
+ -- get program
+ local program = platform.tool(sourcekind)
+
+ -- get complier flags
+ local compflags = sourceflags[sourcefile]
+
+ -- make command
+ local macro = "$(" .. target:name() .. '_' .. sourcekind:upper() .. ")"
+ local command = compiler.compcmd(sourcefile, objectfile, {compflags = table.join(macro, compflags)})
+
+ -- replace program to $(XX)
+ local p, e = command:find("\"" .. program .. "\"", 1, true)
+ if not p then
+ p, e = command:find(program, 1, true)
+ end
+ if p then
+ command = format("%s$(%s)%s", command:sub(1, p - 1), sourcekind:upper(), command:sub(e + 1))
+ end
+
+ -- replace ccache to $(CCACHE)
+ local ccache = false
+ p, e = command:find("ccache", 1, true)
+ if p then
+ command = format("%s$(%s)%s", command:sub(1, p - 1), "CCACHE", command:sub(e + 1))
+ ccache = true
+ end
+
+ -- make head
+ makefile:printf("%s:", objectfile)
+
+ -- make dependence
+ makefile:print(" %s", sourcefile)
+
+ -- make body
+ makefile:print("\t@echo %scompiling.$(mode) %s", ifelse(ccache, "ccache ", ""), sourcefile)
+ _mkdir(makefile, path.directory(objectfile))
+ makefile:writef("\t@%s > %s 2>&1\n", command, _logfile())
+
+ -- make tail
+ makefile:print("")
+end
+
+-- make each objects
+function _make_each_objects(makefile, target, sourcekind, sourcebatch, sourceflags)
+
+ -- make them
+ for index, objectfile in ipairs(sourcebatch.objectfiles) do
+ _make_object(makefile, target, sourcebatch.sourcefiles[index], objectfile, sourceflags)
+ end
+end
+
+-- make single object
+function _make_single_object(makefile, target, sourcekind, sourcebatch, sourceflags)
+
+ -- get source and object files
+ local sourcefiles = sourcebatch.sourcefiles
+ local objectfiles = sourcebatch.objectfiles
+ local dependfiles = sourcebatch.dependfiles
+
+ -- get program
+ local program = platform.tool(sourcekind)
+
+ -- make command
+ local macro = "$(" .. target:name() .. '_' .. sourcekind:upper() .. ")"
+ local command = compiler.compcmd(sourcefiles, objectfiles, {compflags = macro})
+
+ -- replace program to $(XX)
+ local p, e = command:find(program, 1, true)
+ if p then
+ command = format("%s$(%s)%s", command:sub(1, p - 1), sourcekind:upper(), command:sub(e + 1))
+ end
+
+ -- replace ccache to $(CCACHE)
+ local ccache = false
+ p, e = command:find("ccache", 1, true)
+ if p then
+ command = format("%s$(%s)%s", command:sub(1, p - 1), "CCACHE", command:sub(e + 1))
+ ccache = true
+ end
+
+ -- make head
+ makefile:printf("%s:", objectfiles)
+
+ -- make dependence
+ for _, sourcefile in ipairs(sourcefiles) do
+ makefile:printf(" %s", sourcefile)
+ end
+ makefile:print("")
+
+ -- make body
+ for _, sourcefile in ipairs(sourcefiles) do
+ makefile:print("\t@echo %scompiling.$(mode) %s", ifelse(ccache, "ccache ", ""), sourcefile)
+ end
+ _mkdir(makefile, path.directory(objectfiles))
+ makefile:writef("\t@%s > %s 2>&1\n", command, _logfile())
+
+ -- make tail
+ makefile:print("")
+end
+
+-- make phony
+function _make_phony(makefile, target)
+
+ -- make dependence for the dependent targets
+ makefile:printf("%s:", target:name())
+ for _, dep in ipairs(target:get("deps")) do
+ makefile:write(" " .. dep)
+ end
+ makefile:print("")
+end
+
+-- make target
+function _make_target(makefile, target, targetflags)
+
+ -- is phony target?
+ if target:isphony() then
+ return _make_phony(makefile, target)
+ end
+
+ -- make head
+ local targetfile = target:targetfile()
+ makefile:print("%s: %s", target:name(), targetfile)
+ makefile:printf("%s:", targetfile)
+
+ -- make dependence for the dependent targets
+ for _, dep in ipairs(target:get("deps")) do
+ makefile:write(" " .. project.target(dep):targetfile())
+ end
+
+ -- make dependence for objects
+ local objectfiles = target:objectfiles()
+ for _, objectfile in ipairs(objectfiles) do
+ makefile:write(" " .. objectfile)
+ end
+
+ -- make dependence end
+ makefile:print("")
+
+ -- get linker kind
+ local linkerkind = target:linker():kind()
+
+ -- get program
+ local program = platform.tool(linkerkind)
+
+ -- get command
+ local command = target:linkcmd()
+
+ -- replace linkflags to $(XX)
+ local p, e = command:find(os.args(target:linkflags()), 1, true)
+ if p then
+ command = format("%s$(%s_%s)%s", command:sub(1, p - 1), target:name(), (linkerkind:upper():gsub('%-', '_')), command:sub(e + 1))
+ end
+
+ -- replace program to $(XX)
+ p, e = command:find("\"" .. program .. "\"", 1, true)
+ if not p then
+ p, e = command:find(program, 1, true)
+ end
+ if p then
+ command = format("%s$(%s)%s", command:sub(1, p - 1), (linkerkind:upper():gsub('%-', '_')), command:sub(e + 1))
+ end
+
+ -- make body
+ makefile:print("\t@echo linking.$(mode) %s", path.filename(targetfile))
+ _mkdir(makefile, path.directory(targetfile))
+ makefile:writef("\t@%s > %s 2>&1\n", command, _logfile())
+
+ -- TODO make header directories (deprecated)
+ local dstheaderdirs = {}
+ local srcheaders, dstheaders = target:headerfiles()
+ for _, dstheader in ipairs(dstheaders) do
+ dstheaderdirs[path.directory(dstheader)] = true
+ end
+ for dstheaderdir, _ in pairs(dstheaderdirs) do
+ _mkdir(makefile, dstheaderdir)
+ end
+
+ -- copy headers
+ if srcheaders and dstheaders then
+ local i = 1
+ for _, srcheader in ipairs(srcheaders) do
+ local dstheader = dstheaders[i]
+ if dstheader then
+ _cp(makefile, srcheader, dstheader)
+ end
+ i = i + 1
+ end
+ end
+
+ -- make tail
+ makefile:print("")
+
+ -- build source batches
+ for sourcekind, sourcebatch in pairs(target:sourcebatches()) do
+ if not sourcebatch.rulename then
+ -- compile source files to single object at once
+ local sourceflags = targetflags[target:name() .. '_' .. sourcekind:upper()]
+ if type(sourcebatch.objectfiles) == "string" then
+ _make_single_object(makefile, target, sourcekind, sourcebatch, sourceflags)
+ else
+ _make_each_objects(makefile, target, sourcekind, sourcebatch, sourceflags)
+ end
+ end
+ end
+end
+
+-- make all
+function _make_all(makefile)
+
+ -- make variables for ccache
+ makefile:print("CCACHE=ccache")
+
+ -- make variables for source kinds
+ for sourcekind, _ in pairs(language.sourcekinds()) do
+ local program = platform.tool(sourcekind)
+ if program and program ~= "" then
+ makefile:print("%s=%s", sourcekind:upper(), program)
+ end
+ end
+ makefile:print("")
+
+ -- make variables for linker kinds
+ local linkerkinds = {}
+ for _, _linkerkinds in pairs(language.targetkinds()) do
+ table.join2(linkerkinds, _linkerkinds)
+ end
+ for _, linkerkind in ipairs(table.unique(linkerkinds)) do
+ local program = platform.tool(linkerkind)
+ if program and program ~= "" then
+ makefile:print("%s=%s", (linkerkind:upper():gsub('%-', '_')), program)
+ end
+ end
+ makefile:print("")
+
+ -- TODO
+ -- disable precompiled header first
+ for _, target in pairs(project.targets()) do
+ target:set("pcheader", nil)
+ target:set("pcxxheader", nil)
+ end
+
+ -- make variables for target flags
+ local targetflags = {}
+ for targetname, target in pairs(project.targets()) do
+ if not target:isphony() then
+ for sourcekind, sourcebatch in pairs(target:sourcebatches()) do
+ if not sourcebatch.rulename then
+ local commonflags, sourceflags = _make_common_flags(target, sourcekind, sourcebatch)
+ makefile:print("%s_%s=%s", targetname, sourcekind:upper(), os.args(commonflags))
+ targetflags[targetname .. '_' .. sourcekind:upper()] = sourceflags
+ end
+ end
+ makefile:print("%s_%s=%s", targetname, target:linker():kind():upper(), os.args(target:linkflags()))
+ end
+ end
+ makefile:print("")
+
+ -- make all
+ local default = ""
+ for targetname, target in pairs(project.targets()) do
+ local isdefault = target:get("default")
+ if isdefault == nil or isdefault == true then
+ default = default .. " " .. targetname
+ end
+ end
+ makefile:print("default: %s\n", default)
+ local all = ""
+ for targetname, _ in pairs(project.targets()) do
+ all = all .. " " .. targetname
+ end
+ makefile:print("all: %s\n", all)
+ makefile:print(".PHONY: default all %s\n", all)
+
+ -- make it for all targets
+ for _, target in pairs(project.targets()) do
+ _make_target(makefile, target, targetflags)
+ end
+end
+
+-- clean target
+function _clean_target(makefile, target)
+
+ -- make head
+ makefile:printf("clean_%s: ", target:name())
+
+ -- make dependence for the dependent targets
+ for _, dep in ipairs(target:get("deps")) do
+ makefile:write(" clean_" .. dep)
+ end
+
+ -- make dependence end
+ makefile:print("")
+
+ -- make body
+ if not target:isphony() then
+
+ -- remove the target file
+ _remove(makefile, target:targetfile())
+
+ -- remove the symbol file
+ _remove(makefile, target:symbolfile())
+
+ -- remove the object files
+ _remove(makefile, target:objectfiles())
+
+ -- TODO remove the header files (deprecated)
+ local _, dstheaders = target:headers()
+ _remove(makefile, dstheaders)
+ end
+
+ -- make tail
+ makefile:print("")
+end
+
+-- clean all
+function _clean_all(makefile)
+
+ -- clean all
+ local all = ""
+ for targetname, _ in pairs(project.targets()) do
+ all = all .. " clean_" .. targetname
+ end
+ makefile:print("clean: %s\n", all)
+
+ -- clean targets
+ for _, target in pairs(project.targets()) do
+ _clean_target(makefile, target)
+ end
+end
+
+-- make
+function make(outputdir)
+
+ -- enter project directory
+ local oldir = os.cd(os.projectdir())
+
+ -- remove the log makefile first
+ os.rm(_logfile())
+
+ -- open the makefile
+ local makefile = io.open(path.join(outputdir, "makefile"), "w")
+
+ -- make all
+ _make_all(makefile)
+
+ -- clean all
+ _clean_all(makefile)
+
+ -- close the makefile
+ makefile:close()
+
+ -- leave project directory
+ os.cd(oldir)
+end