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%s>', tagname, netbeans.escapepath(prj, rootDir), tagname)
+ else
+ for i = 1, numChildren do
+ _p(d, '<%s>%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, '', 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, '', 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, '%s>', toolName)
+ end