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")