@@ -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
@@ -144,8 +142,7 @@ function m.linkrules(cfg, toolset)
144142 _p (" " )
145143 else
146144 local ldname = toolset .gettoolname (cfg , iif (cfg .language == " C" , " cc" , " cxx" ))
147- local groups = iif (cfg .linkgroups == p .ON , { " -Wl,--start-group" , " -Wl,--end-group" }, {" " , " " })
148- local commands = string.format (" command = %s -o $out %s $in $links $ldflags %s" , ldname , groups [1 ], groups [2 ]);
145+ local commands = string.format (" command = %s -o $out $in $links $ldflags" , ldname );
149146
150147 commands = commands :gsub (" ^%s*(.-)%s*$" , " %1" )
151148 commands = commands :gsub (" %s+" , " " )
@@ -298,12 +295,18 @@ function m.getCFlags(cfg, toolset)
298295
299296 local defines = toolset .getdefines (cfg .defines )
300297 flags = table .join (flags , defines )
298+
299+ local undefines = toolset .getundefines (cfg .undefines )
300+ flags = table .join (flags , undefines )
301301
302- local includedirs = toolset .getincludedirs (cfg , cfg .includedirs , cfg .externalincludedirs , cfg .frameworkdirs )
302+ local includedirs = toolset .getincludedirs (cfg , cfg .includedirs , cfg .externalincludedirs , cfg .frameworkdirs , cfg . includedirsafter )
303303 flags = table .join (flags , includedirs )
304304
305305 local forceincludes = toolset .getforceincludes (cfg )
306306 flags = table .join (flags , forceincludes )
307+
308+ local buildopts = cfg .buildoptions or {}
309+ flags = table .join (flags , buildopts )
307310
308311 return flags
309312end
@@ -317,12 +320,18 @@ function m.getCxxFlags(cfg, toolset)
317320
318321 local defines = toolset .getdefines (cfg .defines )
319322 flags = table .join (flags , defines )
323+
324+ local undefines = toolset .getundefines (cfg .undefines )
325+ flags = table .join (flags , undefines )
320326
321- local includedirs = toolset .getincludedirs (cfg , cfg .includedirs , cfg .externalincludedirs , cfg .frameworkdirs )
327+ local includedirs = toolset .getincludedirs (cfg , cfg .includedirs , cfg .externalincludedirs , cfg .frameworkdirs , cfg . includedirsafter )
322328 flags = table .join (flags , includedirs )
323329
324330 local forceincludes = toolset .getforceincludes (cfg )
325331 flags = table .join (flags , forceincludes )
332+
333+ local buildopts = cfg .buildoptions or {}
334+ flags = table .join (flags , buildopts )
326335
327336 return flags
328337end
@@ -333,6 +342,9 @@ function m.getLdFlags(cfg, toolset)
333342
334343 local toolFlags = toolset .getldflags (cfg )
335344 flags = table .join (flags , toolFlags )
345+
346+ local linkopts = cfg .linkoptions or {}
347+ flags = table .join (flags , linkopts )
336348
337349 local libdirs = toolset .getLibraryDirectories (cfg )
338350 flags = table .join (flags , libdirs )
@@ -441,6 +453,11 @@ function m.buildFiles(cfg)
441453 onleaf = function (node , depth )
442454 local filecfg = fileconfig .getconfig (node , cfg )
443455 if filecfg and not filecfg .flags .ExcludeFromBuild then
456+ -- Skip files with buildaction "None"
457+ if filecfg .buildaction == " None" then
458+ return
459+ end
460+
444461 local toolset = ninja .gettoolset (cfg )
445462 if not (cfg .pchsource and node .abspath == cfg .pchsource and toolset == p .tools .msc ) then
446463 -- Check if this file has custom build commands
@@ -452,6 +469,12 @@ function m.buildFiles(cfg)
452469 table.insert (objList , output )
453470 end
454471 end
472+ elseif filecfg .buildaction == " Copy" then
473+ -- Handle buildaction "Copy"
474+ local output = m .buildCopyFile (cfg , node , filecfg )
475+ if output then
476+ table.insert (objList , output )
477+ end
455478 else
456479 local objFile = m .objectFile (cfg , node , filecfg )
457480 if objFile then
@@ -471,7 +494,24 @@ function m.objectFile(cfg, node, filecfg)
471494 local objdir = path .getrelative (cfg .workspace .location , cfg .objdir )
472495 local ext = path .getextension (node .abspath ):lower ()
473496
474- if path .iscppfile (node .abspath ) or path .iscfile (node .abspath ) then
497+ local shouldCompile = false
498+
499+ -- Check if buildaction is explicitly set to "Compile"
500+ if filecfg and filecfg .buildaction == " Compile" then
501+ shouldCompile = true
502+ -- Check if compileas is set and is a valid language
503+ elseif filecfg and filecfg .compileas and filecfg .compileas ~= " Default" then
504+ if p .languages .isc (filecfg .compileas ) or p .languages .iscpp (filecfg .compileas ) then
505+ shouldCompile = true
506+ end
507+ -- Otherwise check if file extension is compilable
508+ else
509+ if path .iscppfile (node .abspath ) or path .iscfile (node .abspath ) then
510+ shouldCompile = true
511+ end
512+ end
513+
514+ if shouldCompile then
475515 local objname = filecfg .objname or path .getbasename (node .abspath )
476516 local toolset = ninja .gettoolset (cfg )
477517 local objext = toolset .gettooloutputext (" cc" )
@@ -485,20 +525,49 @@ function m.buildFile(cfg, node, filecfg, objFile, pchFile, prebuildTarget)
485525 local ext = path .getextension (node .abspath ):lower ()
486526 local rule = nil
487527 local flags = " "
528+ local extraFlags = {}
529+ local toolset = ninja .gettoolset (cfg )
488530
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 )
531+ if filecfg and filecfg .compileas and filecfg .compileas ~= " Default" then
532+ if p .languages .isc (filecfg .compileas ) then
533+ rule = " cc"
534+ flags = " cflags_" .. ninja .key (cfg )
535+
536+ if toolset .shared and toolset .shared .compileas and toolset .shared .compileas [" C" ] then
537+ table.insert (extraFlags , toolset .shared .compileas [" C" ])
538+ end
539+ elseif p .languages .iscpp (filecfg .compileas ) then
540+ rule = " cxx"
541+ flags = " cxxflags_" .. ninja .key (cfg )
542+
543+ if toolset .shared and toolset .shared .compileas and toolset .shared .compileas [" C++" ] then
544+ table.insert (extraFlags , toolset .shared .compileas [" C++" ])
545+ end
546+ end
547+ elseif filecfg and filecfg .buildaction == " Compile" then
548+ -- Use project language for buildaction "Compile" when compileas is not set
549+ if p .languages .isc (cfg .language ) then
550+ rule = " cc"
551+ flags = " cflags_" .. ninja .key (cfg )
552+ else
553+ rule = " cxx"
554+ flags = " cxxflags_" .. ninja .key (cfg )
555+ end
556+ else
557+ if path .iscfile (node .abspath ) then
558+ rule = " cc"
559+ flags = " cflags_" .. ninja .key (cfg )
560+ elseif path .iscppfile (node .abspath ) then
561+ rule = " cxx"
562+ flags = " cxxflags_" .. ninja .key (cfg )
563+ end
495564 end
496565
497566 if rule then
498567 local relPath = path .getrelative (cfg .workspace .location , node .abspath )
499568 local implicitDeps = " "
500569
501- if pchFile and not filecfg .flags .NoPCH then
570+ if pchFile and filecfg and not filecfg .flags .NoPCH then
502571 implicitDeps = implicitDeps .. " | " .. pchFile
503572 end
504573
@@ -512,9 +581,17 @@ function m.buildFile(cfg, node, filecfg, objFile, pchFile, prebuildTarget)
512581 _p (" build %s: %s %s%s" , objFile , rule , relPath , implicitDeps )
513582
514583 if rule == " cc" then
515- _p (" cflags = $%s" , flags )
584+ if # extraFlags > 0 then
585+ _p (" cflags = $%s %s" , flags , table.concat (extraFlags , " " ))
586+ else
587+ _p (" cflags = $%s" , flags )
588+ end
516589 else
517- _p (" cxxflags = $%s" , flags )
590+ if # extraFlags > 0 then
591+ _p (" cxxflags = $%s %s" , flags , table.concat (extraFlags , " " ))
592+ else
593+ _p (" cxxflags = $%s" , flags )
594+ end
518595 end
519596 end
520597end
@@ -563,6 +640,16 @@ function m.buildCustomFile(cfg, node, filecfg)
563640 return outputs
564641end
565642
643+ function m .buildCopyFile (cfg , node , filecfg )
644+ local relPath = path .getrelative (cfg .workspace .location , node .abspath )
645+ local targetdir = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory )
646+ local output = targetdir .. " /" .. node .name
647+
648+ _p (" build %s: copy %s" , output , relPath )
649+
650+ return output
651+ end
652+
566653function m .linkTarget (cfg )
567654 if not cfg ._objectFiles or # cfg ._objectFiles == 0 then
568655 return
@@ -587,6 +674,22 @@ function m.linkTarget(cfg)
587674 implicitDeps = " | " .. table.concat (wksRelDeps , " " )
588675 end
589676
677+ if cfg .dependson and # cfg .dependson > 0 then
678+ for _ , depname in ipairs (cfg .dependson ) do
679+ local depprj = p .workspace .findproject (cfg .workspace , depname )
680+ if depprj then
681+ local depcfg = project .getconfig (depprj , cfg .buildcfg , cfg .platform )
682+ if depcfg then
683+ local depTarget = path .getrelative (cfg .workspace .location , depcfg .buildtarget .directory ) .. " /" .. depcfg .buildtarget .name
684+ if implicitDeps == " " then
685+ implicitDeps = " |"
686+ end
687+ implicitDeps = implicitDeps .. " " .. depTarget
688+ end
689+ end
690+ end
691+ end
692+
590693 if prelinkTarget then
591694 if implicitDeps == " " then
592695 implicitDeps = " |"
@@ -595,13 +698,9 @@ function m.linkTarget(cfg)
595698 end
596699
597700 local hasPostBuild = # cfg .postbuildcommands > 0 or cfg .postbuildmessage
598- local linkTargetName = targetPath
599-
600- if hasPostBuild then
601- linkTargetName = targetPath .. " .link"
602- end
603701
604- _p (" build %s: %s %s%s" , linkTargetName , rule , table.concat (cfg ._objectFiles , " " ), implicitDeps )
702+ -- Always use the actual target name for the link rule
703+ _p (" build %s: %s %s%s" , targetPath , rule , table.concat (cfg ._objectFiles , " " ), implicitDeps )
605704
606705 if cfg .kind ~= p .STATICLIB then
607706 _p (" ldflags = $ldflags_%s" , ninja .key (cfg ))
@@ -613,7 +712,7 @@ function m.linkTarget(cfg)
613712 end
614713
615714 if hasPostBuild then
616- m .buildPostBuildEvents (cfg , linkTargetName , targetPath )
715+ m .buildPostBuildEvents (cfg , targetPath )
617716 end
618717end
619718
@@ -630,15 +729,15 @@ function m.buildPreBuildEvents(cfg)
630729
631730 if hasMessage and not hasCommands then
632731 _p (" build %s: prebuildmessage" , prebuildTarget )
633- _p (" prebuildmessage = %s " , cfg .prebuildmessage )
732+ _p (" prebuildmessage = \" %s \" " , cfg .prebuildmessage )
634733 elseif hasCommands and not hasMessage then
635734 local commands = os .translateCommandsAndPaths (cfg .prebuildcommands , cfg .project .basedir , cfg .project .location )
636735 local cmdStr = table.concat (commands , " && " )
637736 _p (" build %s: prebuild" , prebuildTarget )
638737 _p (" prebuildcommands = %s" , cmdStr )
639738 else
640739 local commands = os .translateCommandsAndPaths (cfg .prebuildcommands , cfg .project .basedir , cfg .project .location )
641- local cmdStr = " echo " .. ninja . esc ( cfg .prebuildmessage ) .. " && " .. table.concat (commands , " && " )
740+ local cmdStr = " echo \" " .. cfg .prebuildmessage .. " \ " && " .. table.concat (commands , " && " )
642741 _p (" build %s: prebuild" , prebuildTarget )
643742 _p (" prebuildcommands = %s" , cmdStr )
644743 end
@@ -659,42 +758,45 @@ function m.buildPreLinkEvents(cfg)
659758
660759 if hasMessage and not hasCommands then
661760 _p (" build %s: prelinkmessage" , prelinkTarget )
662- _p (" prelinkmessage = %s " , cfg .prelinkmessage )
761+ _p (" prelinkmessage = \" %s \" " , cfg .prelinkmessage )
663762 elseif hasCommands and not hasMessage then
664763 local commands = os .translateCommandsAndPaths (cfg .prelinkcommands , cfg .project .basedir , cfg .project .location )
665764 local cmdStr = table.concat (commands , " && " )
666765 _p (" build %s: prelink" , prelinkTarget )
667766 _p (" prelinkcommands = %s" , cmdStr )
668767 else
669768 local commands = os .translateCommandsAndPaths (cfg .prelinkcommands , cfg .project .basedir , cfg .project .location )
670- local cmdStr = " echo " .. ninja . esc ( cfg .prelinkmessage ) .. " && " .. table.concat (commands , " && " )
769+ local cmdStr = " echo \" " .. cfg .prelinkmessage .. " \ " && " .. table.concat (commands , " && " )
671770 _p (" build %s: prelink" , prelinkTarget )
672771 _p (" prelinkcommands = %s" , cmdStr )
673772 end
674773
675774 return prelinkTarget
676775end
677776
678- function m .buildPostBuildEvents (cfg , linkTarget , finalTarget )
777+ function m .buildPostBuildEvents (cfg , targetPath )
679778 local hasMessage = cfg .postbuildmessage ~= nil
680779 local hasCommands = # cfg .postbuildcommands > 0
681780
682781 if not hasMessage and not hasCommands then
683782 return
684783 end
685784
785+ -- Create a phony intermediate target for the postbuild step
786+ local postbuildPhony = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory ) .. " /" .. cfg .project .name .. " .postbuild"
787+
686788 if hasMessage and not hasCommands then
687- _p (" build %s: postbuildmessage %s" , finalTarget , linkTarget )
688- _p (" postbuildmessage = %s " , cfg .postbuildmessage )
789+ _p (" build %s: postbuildmessage | %s" , postbuildPhony , targetPath )
790+ _p (" postbuildmessage = \" %s \" " , cfg .postbuildmessage )
689791 elseif hasCommands and not hasMessage then
690792 local commands = os .translateCommandsAndPaths (cfg .postbuildcommands , cfg .project .basedir , cfg .project .location )
691793 local cmdStr = table.concat (commands , " && " )
692- _p (" build %s: postbuild %s" , finalTarget , linkTarget )
794+ _p (" build %s: postbuild | %s" , postbuildPhony , targetPath )
693795 _p (" postbuildcommands = %s" , cmdStr )
694796 else
695797 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 )
798+ local cmdStr = " echo \" " .. cfg .postbuildmessage .. " \ " && " .. table.concat (commands , " && " )
799+ _p (" build %s: postbuild | %s" , postbuildPhony , targetPath )
698800 _p (" postbuildcommands = %s" , cmdStr )
699801 end
700802end
@@ -707,7 +809,14 @@ function m.buildTargets(prj)
707809 local targetPath = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory ) .. " /" .. cfg .buildtarget .name
708810 local cfgName = ninja .key (cfg )
709811
710- _p (" build %s: phony %s" , cfgName , targetPath )
812+ -- If there are postbuild events, point to the postbuild target instead
813+ local hasPostBuild = # cfg .postbuildcommands > 0 or cfg .postbuildmessage
814+ if hasPostBuild then
815+ local postbuildTarget = path .getrelative (cfg .workspace .location , cfg .buildtarget .directory ) .. " /" .. cfg .project .name .. " .postbuild"
816+ _p (" build %s: phony %s" , cfgName , postbuildTarget )
817+ else
818+ _p (" build %s: phony %s" , cfgName , targetPath )
819+ end
711820 end
712821
713822 _p (" " )
@@ -720,7 +829,15 @@ function m.projectPhonies(prj)
720829 local firstCfg = project .getfirstconfig (prj )
721830 if firstCfg then
722831 local targetPath = path .getrelative (firstCfg .workspace .location , firstCfg .buildtarget .directory ) .. " /" .. firstCfg .buildtarget .name
723- _p (" build %s: phony %s" , prj .name , targetPath )
832+
833+ -- If there are postbuild events in the first config, point to the postbuild target
834+ local hasPostBuild = # firstCfg .postbuildcommands > 0 or firstCfg .postbuildmessage
835+ if hasPostBuild then
836+ local postbuildTarget = path .getrelative (firstCfg .workspace .location , firstCfg .buildtarget .directory ) .. " /" .. firstCfg .project .name .. " .postbuild"
837+ _p (" build %s: phony %s" , prj .name , postbuildTarget )
838+ else
839+ _p (" build %s: phony %s" , prj .name , targetPath )
840+ end
724841 end
725842
726843 _p (" " )
0 commit comments