premake / premake-core

Premake
https://premake.github.io/
BSD 3-Clause "New" or "Revised" License
3.16k stars 616 forks source link

gmake: Makefile overriding recipe and cannot find dependency file #847

Open Scylardor opened 7 years ago

Scylardor commented 7 years ago

It's been two days I'm puzzled with a C++ project I can't get working with Premake on Ubuntu using Makefiles. It's working just fine on other toolsets/OS like Visual Studio on Windows.

The workspace is composed of a library and a console app linking against it. I have written a set of configurations and platforms that allows me to build the lib in a static or dynamic way, combined with a debug level (debug, release, full optim.). The target and object directories are derived from the selected config / platform pair, and that seems to be a problem. I define targetdir "TestApp/Build/%{cfg.platform}/%{cfg.buildcfg}" and objdir "TestApp/Build/" in the workspace (thus they're the same for all projects, except projects intelligently put their own object files in their own folder).

I managed to reproduce the issue on a very simple sample project, here's the tree structure:

testBreaking
├── premake5.lua
└── TestApp
    ├── Build
    │   ├── Linux_DLL
    │   │   └── Debug
    │   │       ├── libTestCore.so
    │   │       └── TestCore
    │   │           ├── core.d
    │   │           └── core.o
    │   └── Linux_Static
    │       └── Debug
    │           ├── libTestCore.a
    │           └── TestCore
    │               ├── core.d
    │               └── core.o
    ├── Core
    │   ├── core.cpp
    │   ├── core.h
    │   └── Makefile
    ├── Makefile
    ├── Tests
    │   ├── Makefile
    │   └── UnitTests
    │       └── test.cpp
    └── ThirdParty
        └── Catch

So the UnitTests are linking against the Core library, but when comes the time of building the UnitTests project, it fails with an error I don't understand (I use gcc):

pando@pando-VirtualBox:~/Projects/testBreaking/TestApp$ make config=debug_linux_static
==== Building TestCore (debug_linux_static) ====
Creating ../Build/Linux_Static/Debug/TestCore
core.cpp
Linking TestCore
==== Building UnitTests (debug_linux_static) ====
Makefile:582: warning: overriding recipe for target '../Build/Linux_Static/Debug/UnitTests'
Makefile:569: warning: ignoring old recipe for target '../Build/Linux_Static/Debug/UnitTests'
test.cpp
UnitTests/test.cpp:14:1: fatal error: opening dependency file ../Build/Linux_Static/Debug/UnitTests/test.d: No such file or directory
 }
 ^
compilation terminated.
Makefile:613: recipe for target '../Build/Linux_Static/Debug/UnitTests/test.o' failed
make[1]: *** [../Build/Linux_Static/Debug/UnitTests/test.o] Error 1
Makefile:106: recipe for target 'UnitTests' failed
make: *** [UnitTests] Error 2

In fact, I found a workaround : I just need to specify a different objdir for the UnitTests project in the Premake script to make all of this work like a charm. But I don't understand why I need to do it.

And as this project is perfectly working with other toolsets, could it be a problem with how Premake generates makefiles?

I attached a zip containing this entire sample project structure. The premake script is at the root of it. To reproduce:

  1. premake5 gmake
  2. cd TestApp
  3. make config=debug_linux_static (or any other config really)
  4. Core compiles fine, but UnitTests fails

(Optional)

  1. Uncomment the additional objdir in the UnitTests project in Premake script
  2. Try again and observe this time it works properly

Please take a look. Thanks!

testBreaking.zip

PS: some more info on the system:

uname -rvs
Linux 4.10.0-27-generic #30~16.04.2-Ubuntu SMP Thu Jun 29 16:07:46 UTC 2017
make --version
GNU Make 4.1
gcc -v
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 
premake5 --version
premake5 (Premake Build Script Generator) 5.0.0-alpha11
samsinsane commented 6 years ago

This took a bit to figure out, so this is due to a very subtle feature. objdir is more of a "base" than the actual directory, by default it will add /%{cfg.platform}/%{cfg.buildcfg}/%{prj.name} to the end of the specified directory. You can read more about this here, the quick fix is to simply prepend your objdir with !: objdir "!TestApp/Build/".

To extend on to this further, the reason this fails is that your "objdir" becomes TestApp/Build/Linux_Static/Debug/UnitTests for the UnitTests project, the output file of this project is called UnitTests and is output to TestApp/Build/Linux_Static/Debug. This then becomes the same path, but the "objdir" already exists, so the linking stage fails with the beautifully cryptic message.