@@ -34,9 +34,7 @@ function m.generate(prj)
3434 _p (" " ) -- Empty line at end of file
3535end
3636
37- -- Generate all ninja rules (compile, link, etc.)
3837function 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
309313end
@@ -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
328338end
@@ -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 )
@@ -441,6 +454,11 @@ function m.buildFiles(cfg)
441454 onleaf = function (node , depth )
442455 local filecfg = fileconfig .getconfig (node , cfg )
443456 if filecfg and not filecfg .flags .ExcludeFromBuild then
457+ -- Skip files with buildaction "None"
458+ if filecfg .buildaction == " None" then
459+ return
460+ end
461+
444462 local toolset = ninja .gettoolset (cfg )
445463 if not (cfg .pchsource and node .abspath == cfg .pchsource and toolset == p .tools .msc ) then
446464 -- Check if this file has custom build commands
@@ -452,6 +470,12 @@ function m.buildFiles(cfg)
452470 table.insert (objList , output )
453471 end
454472 end
473+ elseif filecfg .buildaction == " Copy" then
474+ -- Handle buildaction "Copy"
475+ local output = m .buildCopyFile (cfg , node , filecfg )
476+ if output then
477+ table.insert (objList , output )
478+ end
455479 else
456480 local objFile = m .objectFile (cfg , node , filecfg )
457481 if objFile then
@@ -471,7 +495,24 @@ function m.objectFile(cfg, node, filecfg)
471495 local objdir = path .getrelative (cfg .workspace .location , cfg .objdir )
472496 local ext = path .getextension (node .abspath ):lower ()
473497
474- if path .iscppfile (node .abspath ) or path .iscfile (node .abspath ) then
498+ local shouldCompile = false
499+
500+ -- Check if buildaction is explicitly set to "Compile"
501+ if filecfg and filecfg .buildaction == " Compile" then
502+ shouldCompile = true
503+ -- Check if compileas is set and is a valid language
504+ elseif filecfg and filecfg .compileas and filecfg .compileas ~= " Default" then
505+ if p .languages .isc (filecfg .compileas ) or p .languages .iscpp (filecfg .compileas ) then
506+ shouldCompile = true
507+ end
508+ -- Otherwise check if file extension is compilable
509+ else
510+ if path .iscppfile (node .abspath ) or path .iscfile (node .abspath ) then
511+ shouldCompile = true
512+ end
513+ end
514+
515+ if shouldCompile then
475516 local objname = filecfg .objname or path .getbasename (node .abspath )
476517 local toolset = ninja .gettoolset (cfg )
477518 local objext = toolset .gettooloutputext (" cc" )
@@ -485,20 +526,49 @@ function m.buildFile(cfg, node, filecfg, objFile, pchFile, prebuildTarget)
485526 local ext = path .getextension (node .abspath ):lower ()
486527 local rule = nil
487528 local flags = " "
529+ local extraFlags = {}
530+ local toolset = ninja .gettoolset (cfg )
488531
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 )
532+ if filecfg and filecfg .compileas and filecfg .compileas ~= " Default" then
533+ if p .languages .isc (filecfg .compileas ) then
534+ rule = " cc"
535+ flags = " cflags_" .. ninja .key (cfg )
536+
537+ if toolset .shared and toolset .shared .compileas and toolset .shared .compileas [" C" ] then
538+ table.insert (extraFlags , toolset .shared .compileas [" C" ])
539+ end
540+ elseif p .languages .iscpp (filecfg .compileas ) then
541+ rule = " cxx"
542+ flags = " cxxflags_" .. ninja .key (cfg )
543+
544+ if toolset .shared and toolset .shared .compileas and toolset .shared .compileas [" C++" ] then
545+ table.insert (extraFlags , toolset .shared .compileas [" C++" ])
546+ end
547+ end
548+ elseif filecfg and filecfg .buildaction == " Compile" then
549+ -- Use project language for buildaction "Compile" when compileas is not set
550+ if p .languages .isc (cfg .language ) then
551+ rule = " cc"
552+ flags = " cflags_" .. ninja .key (cfg )
553+ else
554+ rule = " cxx"
555+ flags = " cxxflags_" .. ninja .key (cfg )
556+ end
557+ else
558+ if path .iscfile (node .abspath ) then
559+ rule = " cc"
560+ flags = " cflags_" .. ninja .key (cfg )
561+ elseif path .iscppfile (node .abspath ) then
562+ rule = " cxx"
563+ flags = " cxxflags_" .. ninja .key (cfg )
564+ end
495565 end
496566
497567 if rule then
498568 local relPath = path .getrelative (cfg .workspace .location , node .abspath )
499569 local implicitDeps = " "
500570
501- if pchFile and not filecfg .flags .NoPCH then
571+ if pchFile and filecfg and not filecfg .flags .NoPCH then
502572 implicitDeps = implicitDeps .. " | " .. pchFile
503573 end
504574
@@ -512,9 +582,17 @@ function m.buildFile(cfg, node, filecfg, objFile, pchFile, prebuildTarget)
512582 _p (" build %s: %s %s%s" , objFile , rule , relPath , implicitDeps )
513583
514584 if rule == " cc" then
515- _p (" cflags = $%s" , flags )
585+ if # extraFlags > 0 then
586+ _p (" cflags = $%s %s" , flags , table.concat (extraFlags , " " ))
587+ else
588+ _p (" cflags = $%s" , flags )
589+ end
516590 else
517- _p (" cxxflags = $%s" , flags )
591+ if # extraFlags > 0 then
592+ _p (" cxxflags = $%s %s" , flags , table.concat (extraFlags , " " ))
593+ else
594+ _p (" cxxflags = $%s" , flags )
595+ end
518596 end
519597 end
520598end
@@ -563,6 +641,16 @@ function m.buildCustomFile(cfg, node, filecfg)
563641 return outputs
564642end
565643
644+ function m .buildCopyFile (cfg , node , filecfg )
645+ local relPath = path .getrelative (cfg .workspace .location , node .abspath )
646+ local targetdir = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory )
647+ local output = targetdir .. " /" .. node .name
648+
649+ _p (" build %s: copy %s" , output , relPath )
650+
651+ return output
652+ end
653+
566654function m .linkTarget (cfg )
567655 if not cfg ._objectFiles or # cfg ._objectFiles == 0 then
568656 return
@@ -595,13 +683,9 @@ function m.linkTarget(cfg)
595683 end
596684
597685 local hasPostBuild = # cfg .postbuildcommands > 0 or cfg .postbuildmessage
598- local linkTargetName = targetPath
599686
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 )
687+ -- Always use the actual target name for the link rule
688+ _p (" build %s: %s %s%s" , targetPath , rule , table.concat (cfg ._objectFiles , " " ), implicitDeps )
605689
606690 if cfg .kind ~= p .STATICLIB then
607691 _p (" ldflags = $ldflags_%s" , ninja .key (cfg ))
@@ -613,7 +697,7 @@ function m.linkTarget(cfg)
613697 end
614698
615699 if hasPostBuild then
616- m .buildPostBuildEvents (cfg , linkTargetName , targetPath )
700+ m .buildPostBuildEvents (cfg , targetPath )
617701 end
618702end
619703
@@ -630,15 +714,15 @@ function m.buildPreBuildEvents(cfg)
630714
631715 if hasMessage and not hasCommands then
632716 _p (" build %s: prebuildmessage" , prebuildTarget )
633- _p (" prebuildmessage = %s " , cfg .prebuildmessage )
717+ _p (" prebuildmessage = \" %s \" " , cfg .prebuildmessage )
634718 elseif hasCommands and not hasMessage then
635719 local commands = os .translateCommandsAndPaths (cfg .prebuildcommands , cfg .project .basedir , cfg .project .location )
636720 local cmdStr = table.concat (commands , " && " )
637721 _p (" build %s: prebuild" , prebuildTarget )
638722 _p (" prebuildcommands = %s" , cmdStr )
639723 else
640724 local commands = os .translateCommandsAndPaths (cfg .prebuildcommands , cfg .project .basedir , cfg .project .location )
641- local cmdStr = " echo " .. ninja . esc ( cfg .prebuildmessage ) .. " && " .. table.concat (commands , " && " )
725+ local cmdStr = " echo \" " .. cfg .prebuildmessage .. " \ " && " .. table.concat (commands , " && " )
642726 _p (" build %s: prebuild" , prebuildTarget )
643727 _p (" prebuildcommands = %s" , cmdStr )
644728 end
@@ -659,42 +743,45 @@ function m.buildPreLinkEvents(cfg)
659743
660744 if hasMessage and not hasCommands then
661745 _p (" build %s: prelinkmessage" , prelinkTarget )
662- _p (" prelinkmessage = %s " , cfg .prelinkmessage )
746+ _p (" prelinkmessage = \" %s \" " , cfg .prelinkmessage )
663747 elseif hasCommands and not hasMessage then
664748 local commands = os .translateCommandsAndPaths (cfg .prelinkcommands , cfg .project .basedir , cfg .project .location )
665749 local cmdStr = table.concat (commands , " && " )
666750 _p (" build %s: prelink" , prelinkTarget )
667751 _p (" prelinkcommands = %s" , cmdStr )
668752 else
669753 local commands = os .translateCommandsAndPaths (cfg .prelinkcommands , cfg .project .basedir , cfg .project .location )
670- local cmdStr = " echo " .. ninja . esc ( cfg .prelinkmessage ) .. " && " .. table.concat (commands , " && " )
754+ local cmdStr = " echo \" " .. cfg .prelinkmessage .. " \ " && " .. table.concat (commands , " && " )
671755 _p (" build %s: prelink" , prelinkTarget )
672756 _p (" prelinkcommands = %s" , cmdStr )
673757 end
674758
675759 return prelinkTarget
676760end
677761
678- function m .buildPostBuildEvents (cfg , linkTarget , finalTarget )
762+ function m .buildPostBuildEvents (cfg , targetPath )
679763 local hasMessage = cfg .postbuildmessage ~= nil
680764 local hasCommands = # cfg .postbuildcommands > 0
681765
682766 if not hasMessage and not hasCommands then
683767 return
684768 end
685769
770+ -- Create a phony intermediate target for the postbuild step
771+ local postbuildPhony = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory ) .. " /" .. cfg .project .name .. " .postbuild"
772+
686773 if hasMessage and not hasCommands then
687- _p (" build %s: postbuildmessage %s" , finalTarget , linkTarget )
688- _p (" postbuildmessage = %s " , cfg .postbuildmessage )
774+ _p (" build %s: postbuildmessage | %s" , postbuildPhony , targetPath )
775+ _p (" postbuildmessage = \" %s \" " , cfg .postbuildmessage )
689776 elseif hasCommands and not hasMessage then
690777 local commands = os .translateCommandsAndPaths (cfg .postbuildcommands , cfg .project .basedir , cfg .project .location )
691778 local cmdStr = table.concat (commands , " && " )
692- _p (" build %s: postbuild %s" , finalTarget , linkTarget )
779+ _p (" build %s: postbuild | %s" , postbuildPhony , targetPath )
693780 _p (" postbuildcommands = %s" , cmdStr )
694781 else
695782 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 )
783+ local cmdStr = " echo \" " .. cfg .postbuildmessage .. " \ " && " .. table.concat (commands , " && " )
784+ _p (" build %s: postbuild | %s" , postbuildPhony , targetPath )
698785 _p (" postbuildcommands = %s" , cmdStr )
699786 end
700787end
@@ -707,7 +794,14 @@ function m.buildTargets(prj)
707794 local targetPath = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory ) .. " /" .. cfg .buildtarget .name
708795 local cfgName = ninja .key (cfg )
709796
710- _p (" build %s: phony %s" , cfgName , targetPath )
797+ -- If there are postbuild events, point to the postbuild target instead
798+ local hasPostBuild = # cfg .postbuildcommands > 0 or cfg .postbuildmessage
799+ if hasPostBuild then
800+ local postbuildTarget = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory ) .. " /" .. cfg .project .name .. " .postbuild"
801+ _p (" build %s: phony %s" , cfgName , postbuildTarget )
802+ else
803+ _p (" build %s: phony %s" , cfgName , targetPath )
804+ end
711805 end
712806
713807 _p (" " )
@@ -720,7 +814,15 @@ function m.projectPhonies(prj)
720814 local firstCfg = project .getfirstconfig (prj )
721815 if firstCfg then
722816 local targetPath = path .getrelative (firstCfg .workspace .location , firstCfg .buildtarget .directory ) .. " /" .. firstCfg .buildtarget .name
723- _p (" build %s: phony %s" , prj .name , targetPath )
817+
818+ -- If there are postbuild events in the first config, point to the postbuild target
819+ local hasPostBuild = # firstCfg .postbuildcommands > 0 or firstCfg .postbuildmessage
820+ if hasPostBuild then
821+ local postbuildTarget = path .getrelative (firstCfg .workspace .location , firstCfg .buildtarget .directory ) .. " /" .. firstCfg .project .name .. " .postbuild"
822+ _p (" build %s: phony %s" , prj .name , postbuildTarget )
823+ else
824+ _p (" build %s: phony %s" , prj .name , targetPath )
825+ end
724826 end
725827
726828 _p (" " )
0 commit comments