diff --git a/CHANGES.txt b/CHANGES.txt index a5092743..60be92d2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -17,6 +17,7 @@ * path.translate() now defaults to Windows-style backslashes * Added NoWarnings flag for Visual Studio (xpol) * Added debugcommand for Visual Studio (xpol) +* Bug 1674173: Allow source files to have the same name ------- diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index 90002689..b475e9e0 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -113,22 +113,9 @@ -- precompiler header rule cpp.pchrules(prj) - --[[ - -- per-file rules - for _, file in ipairs(prj.files) do - if path.iscppfile(file) then - _p('$(OBJDIR)/%s.o: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) - _p('\t@echo $(notdir $<)') - cpp.buildcommand_old(path.iscfile(file)) - elseif (path.getextension(file) == ".rc") then - _p('$(OBJDIR)/%s.res: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) - _p('\t@echo $(notdir $<)') - _p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(RESFLAGS)') - end - end - _p('') - --]] - + -- file building rules + cpp.filerules(prj) + -- include the dependencies, built by GCC (with the -MMD flag) _p('-include $(OBJECTS:%%.o=%%.d)') @@ -222,6 +209,42 @@ end +-- +-- Output the list of file building rules. +-- + + function cpp.filerules(prj) + local tr = project.getsourcetree(prj) + premake.tree.traverse(tr, { + onleaf = function(node, depth) + if path.iscppfile(node.abspath) then + local objectname = project.getfileobject(prj, node.abspath) + _p('$(OBJDIR)/%s.o: %s', make.esc(objectname), make.esc(node.relpath)) + _p('') + end + end + }) + + --[[ + -- per-file rules + for _, file in ipairs(prj.files) do + if path.iscppfile(file) then + _p('$(OBJDIR)/%s.o: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) + _p('\t@echo $(notdir $<)') + cpp.buildcommand_old(path.iscfile(file)) + elseif (path.getextension(file) == ".rc") then + _p('$(OBJDIR)/%s.res: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) + _p('\t@echo $(notdir $<)') + _p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(RESFLAGS)') + end + end + _p('') + --]] + + end + + + -- -- Compile flags -- @@ -290,6 +313,10 @@ return end + -- assign a unique object file name to avoid collisions from + -- files at different folder levels with the same name + local objectname = project.getfileobject(prj, node.abspath) + -- see what set of configurations contains this file local inallcfgs = true for cfg in project.eachconfig(prj) do @@ -303,13 +330,13 @@ -- if this file exists in all configurations, write it to -- the project's list of files if inallcfgs then - _p('\t$(OBJDIR)/%s.o \\', make.esc(node.basename)) + _p('\t$(OBJDIR)/%s.o \\', make.esc(objectname)) -- otherwise add it to the individual configuration lists else for cfg in project.eachconfig(prj) do if incfg[cfg] then - table.insert(cfgfiles[cfg], node.basename) + table.insert(cfgfiles[cfg], objectname) end end end @@ -322,8 +349,8 @@ if #cfgfiles[cfg] > 0 then _p('ifeq ($(config),%s)', make.esc(cfg.shortname)) _p(' OBJECTS += \\') - for _, basename in ipairs(cfgfiles[cfg]) do - _p('\t$(OBJDIR)/%s.o \\', make.esc(basename)) + for _, objectname in ipairs(cfgfiles[cfg]) do + _p('\t$(OBJDIR)/%s.o \\', make.esc(objectname)) end _p('') _p('endif') diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index da405b3c..bbf83eb8 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -775,6 +775,15 @@ end end + -- see if this file needs a modified object file name + local objectname + if path.iscppfile(node.name) then + objectname = project.getfileobject(prj, node.abspath) + if objectname == path.getbasename(node.abspath) then + objectname = nil + end + end + for cfg in project.eachconfig(prj) do -- get any settings specific to this file for this configuration; @@ -789,7 +798,7 @@ local isPchSource = (cfg.pchsource == node.abspath and not cfg.flags.NoPCH) -- only write the element if we have something to say - if compileAs or isPchSource or not filecfg or hasSettings then + if compileAs or isPchSource or not filecfg or hasSettings or objectname then _p(depth,'', path.translate(file.relpath)) for cfg in project.eachconfig(prj) do + local condition = vc2010.condition(cfg) + local filecfg = config.getfileconfig(cfg, file.abspath) if not filecfg then - _p(3,'true', vc2010.condition(cfg)) + _p(3,'true', condition) + end + + local objectname = project.getfileobject(prj, file.abspath) + if objectname ~= path.getbasename(file.abspath) then + _p(3,'$(IntDir)\\%s.obj', condition, objectname) end if cfg.pchsource == file.abspath and not cfg.flags.NoPCH then - _p(3,'Create', vc2010.condition(cfg)) + _p(3,'Create', condition) end end _p(2,'') diff --git a/src/project/project.lua b/src/project/project.lua index 007886d4..9551af9d 100755 --- a/src/project/project.lua +++ b/src/project/project.lua @@ -281,6 +281,44 @@ end +-- +-- Returns a unique object file name for a project source code file. +-- +-- @param prj +-- The project object to query. +-- @param filename +-- The name of the file being compiled to the object file. +-- + + function project.getfileobject(prj, filename) + -- make sure I have the project, and not it's root configuration + prj = prj.project or prj + + -- create a list of objects if necessary + prj.fileobjects = prj.fileobjects or {} + + -- look for the corresponding object file + local basename = path.getbasename(filename) + local uniqued = basename + local i = 0 + + while prj.fileobjects[uniqued] do + -- found a match? + if prj.fileobjects[uniqued] == filename then + return uniqued + end + + -- check a different name + i = i + 1 + uniqued = basename .. i + end + + -- no match, create a new one + prj.fileobjects[uniqued] = filename + return uniqued + end + + -- -- Retrieve the project's file name. -- diff --git a/tests/actions/make/cpp/test_file_rules.lua b/tests/actions/make/cpp/test_file_rules.lua new file mode 100644 index 00000000..eb9706b4 --- /dev/null +++ b/tests/actions/make/cpp/test_file_rules.lua @@ -0,0 +1,42 @@ +-- +-- tests/actions/make/cpp/test_file_rules.lua +-- Validate the makefile source building rules. +-- Copyright (c) 2009-2012 Jason Perkins and the Premake project +-- + + T.make_cpp_file_rules = { } + local suite = T.make_cpp_file_rules + local cpp = premake.make.cpp + local project = premake5.project + + +-- +-- Setup +-- + + local sln, prj + + function suite.setup() + sln = test.createsolution() + end + + local function prepare() + prj = premake.solution.getproject_ng(sln, 1) + cpp.filerules(prj) + end + + +-- +-- Two files with the same base name should have different object files. +-- + + function suite.uniqueObjNames_onBaseNameCollision() + files { "src/hello.cpp", "src/greetings/hello.cpp" } + prepare() + test.capture [[ +$(OBJDIR)/hello.o: src/greetings/hello.cpp + +$(OBJDIR)/hello1.o: src/hello.cpp + + ]] + end diff --git a/tests/actions/make/cpp/test_objects.lua b/tests/actions/make/cpp/test_objects.lua index f7c3e147..2fe15b4f 100644 --- a/tests/actions/make/cpp/test_objects.lua +++ b/tests/actions/make/cpp/test_objects.lua @@ -77,3 +77,19 @@ endif ]] end + +-- +-- Two files with the same base name should have different object files. +-- + + function suite.uniqueObjNames_onBaseNameCollision() + files { "src/hello.cpp", "src/greetings/hello.cpp" } + prepare() + test.capture [[ +OBJECTS := \ + $(OBJDIR)/hello.o \ + $(OBJDIR)/hello1.o \ + + ]] + end + diff --git a/tests/actions/vstudio/vc200x/test_files.lua b/tests/actions/vstudio/vc200x/test_files.lua index 61bb4faa..d9c7d40d 100644 --- a/tests/actions/vstudio/vc200x/test_files.lua +++ b/tests/actions/vstudio/vc200x/test_files.lua @@ -256,3 +256,45 @@ ]] end + + +-- +-- If two files at different folder levels have the same name, a different +-- object file name should be used for each. +-- + + function suite.uniqueObjectNames_onSourceNameCollision() + files { "hello.cpp", "greetings/hello.cpp" } + prepare() + test.capture [[ + + + + + + + + + + + + + ]] + end diff --git a/tests/actions/vstudio/vc2010/test_files.lua b/tests/actions/vstudio/vc2010/test_files.lua index 52de9ff7..750fd69d 100755 --- a/tests/actions/vstudio/vc2010/test_files.lua +++ b/tests/actions/vstudio/vc2010/test_files.lua @@ -129,3 +129,24 @@ ]] end + + +-- +-- If two files at different folder levels have the same name, a different +-- object file name should be used for each. +-- + + function suite.uniqueObjectNames_onSourceNameCollision() + files { "hello.cpp", "greetings/hello.cpp" } + prepare() + test.capture [[ + + + + + $(IntDir)\hello1.obj + $(IntDir)\hello1.obj + + + ]] + end diff --git a/tests/premake4.lua b/tests/premake4.lua index 8b8911ee..c7d0dc51 100644 --- a/tests/premake4.lua +++ b/tests/premake4.lua @@ -158,6 +158,7 @@ dofile("actions/make/solution/test_help_rule.lua") -- Makefile C/C++ projects + dofile("actions/make/cpp/test_file_rules.lua") dofile("actions/make/cpp/test_make_pch.lua") dofile("actions/make/cpp/test_make_linking.lua") dofile("actions/make/cpp/test_objects.lua")