diff --git a/src/_manifest.lua b/src/_manifest.lua index 048c48ed..d0892303 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -53,6 +53,10 @@ "actions/make/make_cpp.lua", "actions/make/make_csharp.lua", + -- NetBeans action + "actions/netbeans/_netbeans.lua", + "actions/netbeans/netbeans_cpp.lua", + -- Visual Studio actions "actions/vstudio/_vstudio.lua", "actions/vstudio/vs2005.lua", diff --git a/src/actions/netbeans/_netbeans.lua b/src/actions/netbeans/_netbeans.lua new file mode 100644 index 00000000..67713c77 --- /dev/null +++ b/src/actions/netbeans/_netbeans.lua @@ -0,0 +1,74 @@ +-- +-- _netbeans.lua +-- Define the netbeans action(s). +-- Copyright (c) 2013 Santo Pfingsten +-- + + premake.netbeans = { } + local netbeans = premake.netbeans + local solution = premake.solution + local project = premake.project + +-- +-- Register the "netbeans" action +-- + + newaction { + trigger = "netbeans", + shortname = "NetBeans", + description = "Generate NetBeans project files", + + valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, + + valid_languages = { "C", "C++" }, + + valid_tools = { + cc = { "clang", "gcc" }, + }, + + onproject = function(prj) + io.esc = netbeans.esc + premake.generate(prj, prj.name .. "/Makefile", netbeans.makefile.generate) + premake.generate(prj, prj.name .. "/nbproject/project.xml", netbeans.projectfile.generate) + premake.generate(prj, prj.name .. "/nbproject/configurations.xml", netbeans.configfile.generate) + end, + + oncleanproject = function(prj) + premake.clean.directory(prj, prj.name) + end + } + +--- +-- Apply XML escaping on a value to be included in an +-- exported project file. +--- + + function netbeans.esc(value) + value = string.gsub(value, '&', "&") + value = value:gsub('"', """) + value = value:gsub("'", "'") + value = value:gsub('<', "<") + value = value:gsub('>', ">") + value = value:gsub('\r', " ") + value = value:gsub('\n', " ") + return value + end + + function netbeans.escapepath(prj, file) + if path.isabsolute(file) then + file = project.getrelative(prj, file) + end + + if not path.isabsolute(file) then + file = path.join('../', file) + end + return premake.esc(file) + end + + function netbeans.gettoolset(cfg) + local toolset = premake.tools[cfg.toolset or "gcc"] + if not toolset then + error("Invalid toolset '" + cfg.toolset + "'") + end + return toolset + end \ No newline at end of file diff --git a/src/actions/netbeans/netbeans_cpp.lua b/src/actions/netbeans/netbeans_cpp.lua new file mode 100644 index 00000000..6651fa59 --- /dev/null +++ b/src/actions/netbeans/netbeans_cpp.lua @@ -0,0 +1,325 @@ +-- +-- netbeans_cpp.lua +-- Generate a C/C++ netbeans project. +-- Copyright (c) 2013 Santo Pfingsten +-- + + premake.netbeans.makefile = {} + premake.netbeans.projectfile = {} + premake.netbeans.configfile = {} + local netbeans = premake.netbeans + local makefile = premake.netbeans.makefile + local projectfile = premake.netbeans.projectfile + local configfile = premake.netbeans.configfile + + local project = premake.project + local config = premake.config + local fileconfig = premake.fileconfig + local tree = premake.tree + +--------------------------------------------------------------------------- +-- +-- Makefile creation +-- +--------------------------------------------------------------------------- + + function makefile.createcommands(prj, key, text) + for cfg in project.eachconfig(prj) do + local commands = cfg[key] + if #commands > 0 then + _x('ifeq ($(CND_CONF),%s)', cfg.shortname) + _p('\t@echo Running %s commands', text) + _p('\t%s', table.implode(commands, "", "", "\n\t")) + _p('endif') + end + end + end + + function makefile.generate(prj) + _p('# Environment') + _p('MKDIR=mkdir') + _p('CP=cp') + _p('CCADMIN=CCadmin') + _p('') + + _p('# build') + _p('build: .build-post') + _p('') + _p('.build-pre:') + makefile.createcommands(prj, 'prebuildcommands', 'pre-build') + _p('') + _p('.build-post: .build-impl') + makefile.createcommands(prj, 'postbuildcommands', 'post-build') + _p('') + + --fixme: prelink doesn't seem possible ? + -- makefile.createcommands(prj, 'prelinkcommands', 'pre-link') + + _p('# clean') + _p('clean: .clean-post') + _p('') + _p('.clean-pre:') + _p('') + _p('.clean-post: .clean-impl') + _p('') + + _p('# clobber') + _p('clobber: .clobber-post') + _p('') + _p('.clobber-pre:') + _p('') + _p('.clobber-post: .clobber-impl') + _p('') + + _p('# all') + _p('all: .all-post') + _p('') + _p('.all-pre:') + _p('') + _p('.all-post: .all-impl') + _p('') + + _p('# build tests') + _p('build-tests: .build-tests-post') + _p('') + _p('.build-tests-pre:') + _p('') + _p('.build-tests-post: .build-tests-impl') + _p('') + + _p('# run tests') + _p('test: .test-post') + _p('') + _p('.test-pre: build-tests') + _p('') + _p('.test-post: .test-impl') + _p('') + + _p('# help') + _p('help: .help-post') + _p('') + _p('.help-pre:') + _p('') + _p('.help-post: .help-impl') + _p('') + + _p('# include project implementation makefile') + _p('include nbproject/Makefile-impl.mk') + _p('') + + _p('# include project make variables') + _p('include nbproject/Makefile-variables.mk') + end + +--------------------------------------------------------------------------- +-- +-- Some shared methods +-- +--------------------------------------------------------------------------- + + function netbeans.rootElements(prj, d, tagname) + -- Build a source tree without removing the root + local tr = tree.new(prj.name) + table.foreachi(prj._.files, function(fcfg) + local flags + if fcfg.vpath ~= fcfg.relpath then + flags = { trim = false } + end + local parent = tree.add(tr, path.getdirectory(fcfg.vpath), flags) + local node = tree.insert(parent, tree.new(path.getname(fcfg.vpath))) + setmetatable(node, { __index = fcfg }) + end) + tree.sort(tr) + + -- Need more than one child + while #tr.children == 1 do + tr = tr.children[1] + if tr.trim == false then + break + end + end + + -- If there are files inside this folder, use the parent folder + local numChildren = #tr.children + local rootDir = nil + for i = 1, numChildren do + -- Only files have relpath set + if tr.children[i].relpath then + rootDir = path.getdirectory(tr.children[i].relpath) + break + end + end + + if rootDir ~= nil then + _p(d, '<%s>%s', tagname, netbeans.escapepath(prj, rootDir), tagname) + else + for i = 1, numChildren do + _p(d, '<%s>%s', tagname, netbeans.escapepath(prj, tr.children[i].path), tagname) + end + end + end + + function netbeans.kindToType(kind) + if kind == "WindowedApp" or kind == "ConsoleApp" then + return 1 + elseif kind == "StaticLib" then + return 3 + elseif kind == "SharedLib" then + return 2 + end + end + +--------------------------------------------------------------------------- +-- +-- Project file creation +-- +--------------------------------------------------------------------------- + + function projectfile.generate(prj) + _p('') + _p('', premake.action.current().shortname) + _p('') + _p(1, 'org.netbeans.modules.cnd.makeproject') + _p(1, '') + _p(2, '') + _p(3, '%s', premake.esc(prj.name)) + _p(3, 'c') + _p(3, 'cpp') + _p(3, 'h') + _p(3, 'UTF-8') + _p(3, '') + _p(3, '') + netbeans.rootElements(prj, 4, 'sourceRootElem') + _p(3, '') + _p(3, '') + for cfg in project.eachconfig(prj) do + _p(4, '') + _p(5, '%s', premake.esc(cfg.shortname)) + _p(5, '%d', netbeans.kindToType(cfg.kind)) + _p(4, '') + end + _p(3, '') + _p(2, '') + _p(1, '') + _p('') + end + +--------------------------------------------------------------------------- +-- +-- Configurations file creation +-- +--------------------------------------------------------------------------- + + function configfile.generate(prj) + _p('') + _p('', premake.esc(premake.action.current().shortname)) + _p('') + _p(1, '') + _p(2, '') + + local tr = project.getsourcetree(prj) + tree.sort(tr) + tree.traverse(tr, { + onbranchenter = function(node, depth) + if depth > 0 then + _p(depth + 2, '', premake.esc(node.name), premake.esc(node.name)) + end + end, + onbranchexit = function(node, depth) + if depth > 0 then + _p(depth + 2, '') + end + end, + + onleaf = function(node, depth) + _p(depth + 2, '%s', netbeans.escapepath(prj, node.relpath)) + end + }, true) + + _p(2, '') + _p(2, '') + _p(3, 'Makefile') + _p(2, '') + + _p(1, '') + _p(1, '') + netbeans.rootElements(prj, 2, 'Elem') + _p(1, '') + _p(1, 'Makefile') + + _p(1, '') + for cfg in project.eachconfig(prj) do + configfile.conf(prj, cfg) + end + _p(1, '') + _p('') + end + + function configfile.conf(prj, cfg) + local toolset = netbeans.gettoolset(cfg) + + _p(2, '', premake.esc(cfg.shortname), netbeans.kindToType(cfg.kind)) + _p(3, '') + _p(4, 'LOCAL_SOURCES') + _p(4, 'default') + _p(4, 'true') + _p(4, 'false') + _p(3, '') + _p(3, '') + + configfile.confTool(cfg, 'cTool', table.join(toolset.getcppflags(cfg), toolset.getcflags(cfg), cfg.buildoptions)) + configfile.confTool(cfg, 'ccTool', table.join(toolset.getcppflags(cfg), toolset.getcflags(cfg), cfg.buildoptions)) + + local output = netbeans.escapepath(prj, path.join(cfg.buildtarget.directory, cfg.buildtarget.name)) + if cfg.kind == "StaticLib" then + _p(4, '') + _p(5, '%s', output) + _p(4, '') + else + _p(4, '') + _p(5, '') + for _, libdir in ipairs(config.getlinks(cfg, "siblings", "directory")) do + _p(6, '%s', netbeans.escapepath(prj, libdir)) + end + _p(5, '') + _p(5, '') + local scope = iif(explicit, "all", "system") + for _, libname in ipairs(config.getlinks(cfg, scope, "fullpath")) do + _p(6, '%s', premake.esc(path.getbasename(libname))) + end + _p(5, '') + _p(5, '%s', premake.esc(table.concat(table.join(toolset.getldflags(cfg), cfg.linkoptions), " "))) + _p(5, '%s', output) + _p(4, '') + end + _p(3, '') + + for _, file in ipairs(prj.files) do + local tool = 3; + if path.iscfile(file) then tool = 0 + elseif path.iscppfile(file) then tool = 1 + else tool = 3 + end + _p(3, '', netbeans.escapepath(prj, file), tool) + end + _p(2, '') + end + + function configfile.confTool(cfg, toolName, flags) + _p(4, '<%s>', toolName) + if not config.isDebugBuild(cfg) and cfg.flags.ReleaseRuntime then + _p(5, '5') + end + _p(5, '') + for _, incdir in ipairs(cfg.includedirs) do + _p(6, '%s', netbeans.escapepath(cfg.project, incdir)) + end + _p(5, '') + _p(5, '') + for _, definename in ipairs(cfg.defines) do + _p(6, '%s', premake.esc(definename)) + end + _p(5, '') + _p(5, '%s', premake.esc(table.concat(flags, " "))) + _p(4, '', toolName) + end