premake / premake-core

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

g++/clang++ not found while linking when installed in a custom location #1961

Open complexmath opened 2 years ago

complexmath commented 2 years ago

I'm building on a Linux system (WSL2) that doesn't have gcc or clang installed in /usr. Instead, it's installed in my local project directory. I've added the following to premake5.lua:

bindirs { "path/to/gcc/bin" }

The relevant portions of my generated makefile are:

LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)

$(OBJDIR)/main.o: source/main.cpp
    @echo $(notdir $<)
    $(SILENT) $(EXE_PATHS) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

While building I get an error like:

/bin/sh: 1: g++: not found

I think the generated LINKCMD above should really look like:

LINKCMD = $(EXE_PATHS) $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
nickclark2016 commented 2 years ago

That is most likely Make not knowing where your C++ compiler is, not a bug in Premake. Is GCC/G++ on your path? Have you tried passing CXX as a parameter to make?

complexmath commented 2 years ago

My understanding is that this is what the bindirs instruction is for in premake. Is this not the case? Like because of the $(EXE_PATHS) param in the generated build instruction, make is able to find the compiler to generate object files just fine. But because this is missing from the link command, it can't do the same for that step. I agree that I could fix this by doing something like:

PATH=/path/to/gcc/bin:$PATH make

But it doesn't seem like this should be necessary. Assuming I had GCC installed in the default location and a different version installed elsewhere that I was pointing to via bindirs for this build, I'd be using a different version of G++ for the link step than I used to generate object files.

nickclark2016 commented 2 years ago

Can you share more of the generated makefile?

complexmath commented 2 years ago

Makefile:

all: $(PROJECTS)

app: proj-test

proj-test:
ifneq (,$(proj_test_config))
    @echo "==== Building proj-test ($(proj_test_config)) ===="
    @${MAKE} --no-print-directory -C . -f proj-test.make config=$(proj_test_config)
endif

proj-test.make:

ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
LDDEPS +=
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
EXECUTABLE_PATHS = "_build/tools/gcc/bin"
EXE_PATHS = export PATH=$(EXECUTABLE_PATHS):$$PATH;
...
# File sets
# #############################################

GENERATED :=
OBJECTS :=

GENERATED += $(OBJDIR)/main.o
OBJECTS += $(OBJDIR)/main.o

# Rules
# #############################################

all: $(TARGET)
    @:

$(TARGET): $(GENERATED) $(OBJECTS) $(LDDEPS) | $(TARGETDIR)
    $(PRELINKCMDS)
    @echo Linking proj-test
    $(SILENT) $(LINKCMD)
    $(POSTBUILDCMDS)

$(TARGETDIR):
    @echo Creating $(TARGETDIR)
ifeq (posix,$(SHELLTYPE))
    $(SILENT) mkdir -p $(TARGETDIR)
else
    $(SILENT) mkdir $(subst /,\\,$(TARGETDIR))
endif

$(OBJDIR):
    @echo Creating $(OBJDIR)
ifeq (posix,$(SHELLTYPE))
    $(SILENT) mkdir -p $(OBJDIR)
else
    $(SILENT) mkdir $(subst /,\\,$(OBJDIR))
endif
...
# File Rules
# #############################################

$(OBJDIR)/main.o: source/main.cpp
    @echo $(notdir $<)
    $(SILENT) $(EXE_PATHS) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

-include $(OBJECTS:%.o=%.d)
ifneq (,$(PCH))
  -include $(PCH_PLACEHOLDER).d
endif

From looking at the premake code, I found this for example, which injects the bindirs for the build step: https://github.com/premake/premake-core/blob/master/modules/gmake/gmake_cpp.lua#L257

But the LINKCMD isn't given the same treatment, as you can see above. Maybe not a huge issue if this is C and you can link with ar, but potentially more of an issue for C++ when you typically link via the compiler.

nickclark2016 commented 2 years ago

I believe that bindirs are used for using custom tools in custom build steps (passing paths to where you have you build tools), not to where CC, CXX, etc. I'd like @starkos or @samsinsane to confirm my guess though.

complexmath commented 2 years ago

Then shouldn't the $(EXE_PATHS) bit be missing from the build rules involving $(CXX)? Ultimately, the issue here is the inconsistency in path handling between the compile and link steps.

nickclark2016 commented 2 years ago

Good catch. I'll investigate further and get back to you.

Jarod42 commented 2 years ago

BTW, https://premake.github.io/docs/bindirs/ has no real documentation.

nickclark2016 commented 2 years ago

BTW, https://premake.github.io/docs/bindirs/ has no real documentation.

Yup, that's a definite issue. I think it's lead to some of my confusion as well.

samsinsane commented 2 years ago

@nickclark2016 That is correct, bindirs was intended for the custom build rules system. The new gmake2 action built C++ support around the rules system, which has created this weird scenario of bindirs impacting regular project compilation.

@complexmath for GCC there is gccprefix which might work for your situation? It won't replicate PATH=<path>:$PATH but it might otherwise do what you're expecting? Alternatively, you could look into using makesettings to configure the paths as you expect? This will inject whatever Makefile settings you want just after the EXE_PATHS output but before the pre-build commands output.

Enhex commented 1 year ago

what if there's more than 1 version of the same compiler installed? does bindirs allow choosing one over the other?