Skip to content

Commit 66f85b6

Browse files
committed
Add buildoptions, linkoptions support
1 parent 1fc5b66 commit 66f85b6

File tree

9 files changed

+650
-143
lines changed

9 files changed

+650
-143
lines changed

modules/ninja/_preload.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ newaction {
3333
elseif target == p.EMSCRIPTEN then
3434
return "emcc"
3535
elseif target == p.WINDOWS then
36-
return "v143"
36+
return "msc"
3737
else
3838
return "gcc"
3939
end

modules/ninja/ninja.lua

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,14 @@ p.modules.ninja._VERSION = p._VERSION
1212

1313
local ninja = p.modules.ninja
1414

15-
--
16-
-- Escape a string so it can be written to a Ninja build file.
17-
-- Ninja variables are expanded into shell commands, so we need to escape
18-
-- shell special characters as well as Ninja special characters.
19-
--
2015
function ninja.esc(value)
2116
value = value:gsub("%$", "$$")
2217
value = value:gsub(":", "$:")
2318
value = value:gsub("\n", "$\n")
24-
value = value:gsub(" ", "$ ")
2519
value = value:gsub('%(', '\\(')
2620
value = value:gsub('%)', '\\)')
2721
value = value:gsub('"', '\\"')
22+
value = value:gsub(" ", "\\ ")
2823

2924
return value
3025
end

modules/ninja/ninja_cpp.lua

Lines changed: 98 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ function m.generate(prj)
3434
_p("") -- Empty line at end of file
3535
end
3636

37-
-- Generate all ninja rules (compile, link, etc.)
3837
function m.rules(prj)
39-
-- Generate rules for each configuration to handle different toolsets
4038
local rulesDone = {}
4139

4240
for cfg in project.eachconfig(prj) do
@@ -298,12 +296,18 @@ function m.getCFlags(cfg, toolset)
298296

299297
local defines = toolset.getdefines(cfg.defines)
300298
flags = table.join(flags, defines)
299+
300+
local undefines = toolset.getundefines(cfg.undefines)
301+
flags = table.join(flags, undefines)
301302

302303
local includedirs = toolset.getincludedirs(cfg, cfg.includedirs, cfg.externalincludedirs, cfg.frameworkdirs)
303304
flags = table.join(flags, includedirs)
304305

305306
local forceincludes = toolset.getforceincludes(cfg)
306307
flags = table.join(flags, forceincludes)
308+
309+
local buildopts = cfg.buildoptions or {}
310+
flags = table.join(flags, buildopts)
307311

308312
return flags
309313
end
@@ -317,12 +321,18 @@ function m.getCxxFlags(cfg, toolset)
317321

318322
local defines = toolset.getdefines(cfg.defines)
319323
flags = table.join(flags, defines)
324+
325+
local undefines = toolset.getundefines(cfg.undefines)
326+
flags = table.join(flags, undefines)
320327

321328
local includedirs = toolset.getincludedirs(cfg, cfg.includedirs, cfg.externalincludedirs, cfg.frameworkdirs)
322329
flags = table.join(flags, includedirs)
323330

324331
local forceincludes = toolset.getforceincludes(cfg)
325332
flags = table.join(flags, forceincludes)
333+
334+
local buildopts = cfg.buildoptions or {}
335+
flags = table.join(flags, buildopts)
326336

327337
return flags
328338
end
@@ -333,6 +343,9 @@ function m.getLdFlags(cfg, toolset)
333343

334344
local toolFlags = toolset.getldflags(cfg)
335345
flags = table.join(flags, toolFlags)
346+
347+
local linkopts = cfg.linkoptions or {}
348+
flags = table.join(flags, linkopts)
336349

337350
local libdirs = toolset.getLibraryDirectories(cfg)
338351
flags = table.join(flags, libdirs)
@@ -471,7 +484,19 @@ function m.objectFile(cfg, node, filecfg)
471484
local objdir = path.getrelative(cfg.workspace.location, cfg.objdir)
472485
local ext = path.getextension(node.abspath):lower()
473486

474-
if path.iscppfile(node.abspath) or path.iscfile(node.abspath) then
487+
local shouldCompile = false
488+
489+
if filecfg and filecfg.compileas and filecfg.compileas ~= "Default" then
490+
if p.languages.isc(filecfg.compileas) or p.languages.iscpp(filecfg.compileas) then
491+
shouldCompile = true
492+
end
493+
else
494+
if path.iscppfile(node.abspath) or path.iscfile(node.abspath) then
495+
shouldCompile = true
496+
end
497+
end
498+
499+
if shouldCompile then
475500
local objname = filecfg.objname or path.getbasename(node.abspath)
476501
local toolset = ninja.gettoolset(cfg)
477502
local objext = toolset.gettooloutputext("cc")
@@ -485,20 +510,40 @@ function m.buildFile(cfg, node, filecfg, objFile, pchFile, prebuildTarget)
485510
local ext = path.getextension(node.abspath):lower()
486511
local rule = nil
487512
local flags = ""
513+
local extraFlags = {}
514+
local toolset = ninja.gettoolset(cfg)
488515

489-
if path.iscfile(node.abspath) then
490-
rule = "cc"
491-
flags = "cflags_" .. ninja.key(cfg)
492-
elseif path.iscppfile(node.abspath) then
493-
rule = "cxx"
494-
flags = "cxxflags_" .. ninja.key(cfg)
516+
if filecfg and filecfg.compileas and filecfg.compileas ~= "Default" then
517+
if p.languages.isc(filecfg.compileas) then
518+
rule = "cc"
519+
flags = "cflags_" .. ninja.key(cfg)
520+
521+
if toolset.shared and toolset.shared.compileas and toolset.shared.compileas["C"] then
522+
table.insert(extraFlags, toolset.shared.compileas["C"])
523+
end
524+
elseif p.languages.iscpp(filecfg.compileas) then
525+
rule = "cxx"
526+
flags = "cxxflags_" .. ninja.key(cfg)
527+
528+
if toolset.shared and toolset.shared.compileas and toolset.shared.compileas["C++"] then
529+
table.insert(extraFlags, toolset.shared.compileas["C++"])
530+
end
531+
end
532+
else
533+
if path.iscfile(node.abspath) then
534+
rule = "cc"
535+
flags = "cflags_" .. ninja.key(cfg)
536+
elseif path.iscppfile(node.abspath) then
537+
rule = "cxx"
538+
flags = "cxxflags_" .. ninja.key(cfg)
539+
end
495540
end
496541

497542
if rule then
498543
local relPath = path.getrelative(cfg.workspace.location, node.abspath)
499544
local implicitDeps = ""
500545

501-
if pchFile and not filecfg.flags.NoPCH then
546+
if pchFile and filecfg and not filecfg.flags.NoPCH then
502547
implicitDeps = implicitDeps .. " | " .. pchFile
503548
end
504549

@@ -512,9 +557,17 @@ function m.buildFile(cfg, node, filecfg, objFile, pchFile, prebuildTarget)
512557
_p("build %s: %s %s%s", objFile, rule, relPath, implicitDeps)
513558

514559
if rule == "cc" then
515-
_p(" cflags = $%s", flags)
560+
if #extraFlags > 0 then
561+
_p(" cflags = $%s %s", flags, table.concat(extraFlags, " "))
562+
else
563+
_p(" cflags = $%s", flags)
564+
end
516565
else
517-
_p(" cxxflags = $%s", flags)
566+
if #extraFlags > 0 then
567+
_p(" cxxflags = $%s %s", flags, table.concat(extraFlags, " "))
568+
else
569+
_p(" cxxflags = $%s", flags)
570+
end
518571
end
519572
end
520573
end
@@ -595,13 +648,9 @@ function m.linkTarget(cfg)
595648
end
596649

597650
local hasPostBuild = #cfg.postbuildcommands > 0 or cfg.postbuildmessage
598-
local linkTargetName = targetPath
599651

600-
if hasPostBuild then
601-
linkTargetName = targetPath .. ".link"
602-
end
603-
604-
_p("build %s: %s %s%s", linkTargetName, rule, table.concat(cfg._objectFiles, " "), implicitDeps)
652+
-- Always use the actual target name for the link rule
653+
_p("build %s: %s %s%s", targetPath, rule, table.concat(cfg._objectFiles, " "), implicitDeps)
605654

606655
if cfg.kind ~= p.STATICLIB then
607656
_p(" ldflags = $ldflags_%s", ninja.key(cfg))
@@ -613,7 +662,7 @@ function m.linkTarget(cfg)
613662
end
614663

615664
if hasPostBuild then
616-
m.buildPostBuildEvents(cfg, linkTargetName, targetPath)
665+
m.buildPostBuildEvents(cfg, targetPath)
617666
end
618667
end
619668

@@ -630,15 +679,15 @@ function m.buildPreBuildEvents(cfg)
630679

631680
if hasMessage and not hasCommands then
632681
_p("build %s: prebuildmessage", prebuildTarget)
633-
_p(" prebuildmessage = %s", cfg.prebuildmessage)
682+
_p(" prebuildmessage = \"%s\"", cfg.prebuildmessage)
634683
elseif hasCommands and not hasMessage then
635684
local commands = os.translateCommandsAndPaths(cfg.prebuildcommands, cfg.project.basedir, cfg.project.location)
636685
local cmdStr = table.concat(commands, " && ")
637686
_p("build %s: prebuild", prebuildTarget)
638687
_p(" prebuildcommands = %s", cmdStr)
639688
else
640689
local commands = os.translateCommandsAndPaths(cfg.prebuildcommands, cfg.project.basedir, cfg.project.location)
641-
local cmdStr = "echo " .. ninja.esc(cfg.prebuildmessage) .. " && " .. table.concat(commands, " && ")
690+
local cmdStr = "echo \"" .. cfg.prebuildmessage .. "\" && " .. table.concat(commands, " && ")
642691
_p("build %s: prebuild", prebuildTarget)
643692
_p(" prebuildcommands = %s", cmdStr)
644693
end
@@ -659,42 +708,45 @@ function m.buildPreLinkEvents(cfg)
659708

660709
if hasMessage and not hasCommands then
661710
_p("build %s: prelinkmessage", prelinkTarget)
662-
_p(" prelinkmessage = %s", cfg.prelinkmessage)
711+
_p(" prelinkmessage = \"%s\"", cfg.prelinkmessage)
663712
elseif hasCommands and not hasMessage then
664713
local commands = os.translateCommandsAndPaths(cfg.prelinkcommands, cfg.project.basedir, cfg.project.location)
665714
local cmdStr = table.concat(commands, " && ")
666715
_p("build %s: prelink", prelinkTarget)
667716
_p(" prelinkcommands = %s", cmdStr)
668717
else
669718
local commands = os.translateCommandsAndPaths(cfg.prelinkcommands, cfg.project.basedir, cfg.project.location)
670-
local cmdStr = "echo " .. ninja.esc(cfg.prelinkmessage) .. " && " .. table.concat(commands, " && ")
719+
local cmdStr = "echo \"" .. cfg.prelinkmessage .. "\" && " .. table.concat(commands, " && ")
671720
_p("build %s: prelink", prelinkTarget)
672721
_p(" prelinkcommands = %s", cmdStr)
673722
end
674723

675724
return prelinkTarget
676725
end
677726

678-
function m.buildPostBuildEvents(cfg, linkTarget, finalTarget)
727+
function m.buildPostBuildEvents(cfg, targetPath)
679728
local hasMessage = cfg.postbuildmessage ~= nil
680729
local hasCommands = #cfg.postbuildcommands > 0
681730

682731
if not hasMessage and not hasCommands then
683732
return
684733
end
685734

735+
-- Create a phony intermediate target for the postbuild step
736+
local postbuildPhony = path.getrelative(cfg.workspace.location, cfg.buildtarget.directory) .. "/" .. cfg.project.name .. ".postbuild"
737+
686738
if hasMessage and not hasCommands then
687-
_p("build %s: postbuildmessage %s", finalTarget, linkTarget)
688-
_p(" postbuildmessage = %s", cfg.postbuildmessage)
739+
_p("build %s: postbuildmessage | %s", postbuildPhony, targetPath)
740+
_p(" postbuildmessage = \"%s\"", cfg.postbuildmessage)
689741
elseif hasCommands and not hasMessage then
690742
local commands = os.translateCommandsAndPaths(cfg.postbuildcommands, cfg.project.basedir, cfg.project.location)
691743
local cmdStr = table.concat(commands, " && ")
692-
_p("build %s: postbuild %s", finalTarget, linkTarget)
744+
_p("build %s: postbuild | %s", postbuildPhony, targetPath)
693745
_p(" postbuildcommands = %s", cmdStr)
694746
else
695747
local commands = os.translateCommandsAndPaths(cfg.postbuildcommands, cfg.project.basedir, cfg.project.location)
696-
local cmdStr = "echo " .. ninja.esc(cfg.postbuildmessage) .. " && " .. table.concat(commands, " && ")
697-
_p("build %s: postbuild %s", finalTarget, linkTarget)
748+
local cmdStr = "echo \"" .. cfg.postbuildmessage .. "\" && " .. table.concat(commands, " && ")
749+
_p("build %s: postbuild | %s", postbuildPhony, targetPath)
698750
_p(" postbuildcommands = %s", cmdStr)
699751
end
700752
end
@@ -707,7 +759,14 @@ function m.buildTargets(prj)
707759
local targetPath = path.getrelative(cfg.workspace.location, cfg.buildtarget.directory) .. "/" .. cfg.buildtarget.name
708760
local cfgName = ninja.key(cfg)
709761

710-
_p("build %s: phony %s", cfgName, targetPath)
762+
-- If there are postbuild events, point to the postbuild target instead
763+
local hasPostBuild = #cfg.postbuildcommands > 0 or cfg.postbuildmessage
764+
if hasPostBuild then
765+
local postbuildTarget = path.getrelative(cfg.workspace.location, cfg.buildtarget.directory) .. "/" .. cfg.project.name .. ".postbuild"
766+
_p("build %s: phony %s", cfgName, postbuildTarget)
767+
else
768+
_p("build %s: phony %s", cfgName, targetPath)
769+
end
711770
end
712771

713772
_p("")
@@ -720,7 +779,15 @@ function m.projectPhonies(prj)
720779
local firstCfg = project.getfirstconfig(prj)
721780
if firstCfg then
722781
local targetPath = path.getrelative(firstCfg.workspace.location, firstCfg.buildtarget.directory) .. "/" .. firstCfg.buildtarget.name
723-
_p("build %s: phony %s", prj.name, targetPath)
782+
783+
-- If there are postbuild events in the first config, point to the postbuild target
784+
local hasPostBuild = #firstCfg.postbuildcommands > 0 or firstCfg.postbuildmessage
785+
if hasPostBuild then
786+
local postbuildTarget = path.getrelative(firstCfg.workspace.location, firstCfg.buildtarget.directory) .. "/" .. firstCfg.project.name .. ".postbuild"
787+
_p("build %s: phony %s", prj.name, postbuildTarget)
788+
else
789+
_p("build %s: phony %s", prj.name, targetPath)
790+
end
724791
end
725792

726793
_p("")

modules/ninja/tests/_tests.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require("ninja")
99

1010
return {
1111
"test_build_rules.lua",
12+
"test_ninja_compileas.lua",
1213
"test_ninja_config.lua",
1314
"test_ninja_custom_build.lua",
1415
"test_ninja_pch.lua",

0 commit comments

Comments
 (0)