Eclipse 2022-09 automatically generated makefile lacks a target - c

I am unable to build a project after importing a git project as a C/C++ Makefile project with existing code. When configuring Eclipse to automatically generate a makefile the resulting makefile does not have the BUILD_ARTIFACT_NAME variable set and as a result does not have any main-build target set. How do I configure this imported project to properly generate a makefile?
I have included a section of the resulting makefile here. BUILD_ARTIFACT_NAME is blank, and there is no target specified as shown here:
BUILD_ARTIFACT_NAME :=
BUILD_ARTIFACT_EXTENSION :=
BUILD_ARTIFACT_PREFIX :=
BUILD_ARTIFACT := $(BUILD_ARTIFACT_PREFIX)$(BUILD_ARTIFACT_NAME)$(if
$(BUILD_ARTIFACT_EXTENSION),.$(BUILD_ARTIFACT_EXTENSION),)
all: main-build
main-build:
: $(OBJS) $(USER_OBJS) makefile $(OPTIONAL_TOOL_DEPS)
#echo 'Building target: $#'
#echo 'Invoking: GCC C++ Linker'
g++ -o $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
I have another reference C project that does generate the makefile properly. This project I built from scratch; I did not import it.
This project's makefile looks like this:
BUILD_ARTIFACT_NAME := ioctl
BUILD_ARTIFACT_EXTENSION :=
BUILD_ARTIFACT_PREFIX :=
BUILD_ARTIFACT := $(BUILD_ARTIFACT_PREFIX)$(BUILD_ARTIFACT_NAME)$(if
$(BUILD_ARTIFACT_EXTENSION),.$(BUILD_ARTIFACT_EXTENSION),)
all: main-build
main-build: ioctl
ioctl: $(OBJS) $(USER_OBJS) makefile $(OPTIONAL_TOOL_DEPS)
#echo 'Building target: $#'
#echo 'Invoking: GCC C Linker'
gcc -o "ioctl" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
Further investigating between the two Eclipse workspaces show that within:
Project Properties / C/C++ Build / Build Variables / Show system variables
I see that within the working project the following two variables are set:
BuildArtifactFileBaseName: ${ProjName}
BuildArtifactFileName: ${ProjName}
The project that does not generate the makefile properly does not have these two variables set. Unfortunately, setting the variables to ${ProjName} does not resolve the issue, nor does setting them to some string "pleaseBuild". What am I missing here? If I edit the makefile external of eclipse and add a target, then the project builds.

Related

What is Eclipse CDT is doing with 'make' under the hood

I'm on Windows 7 and have MinGW/gcc installed. I'm using the Eclipse CDT plugin to compile and build my first simple C programs, and am trying to follow what exactly the plugin is doing under the hood.
I create a new "Hello World!" C project with the following directory structure:
helloworld/
src/
helloworld.c
Where helloworld.c is:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
puts("Hello World!");
return EXIT_SUCCESS;
}
So I created a Run Configuration in Debug Mode (as opposed to "Release Mode", not a "Debug Configuration" in typical Eclipse parlance!) and ran my app, and it works beautifully, printing "Hello World!" to the Eclipse console.
Now I'm looking on my file system and the file/project structure is like so:
helloworld/
src/
helloworld.c
Debug/
src/
helloworld.d
helloworld.o
subdir.mk
helloworld.exe
makefile
objects.mk
source.mk
I assume that running my Run Configuration in Eclipse (hence compiling/building/running helloworld inside Eclipse) created everything under Debug. Furthermore I assume that helloworld.d and helloworld.o are compiled binaries, and that helloworld.exe is the packaged executable containing those binaries and everything they'red linked to (stdio and stdlib). I also assume makefile is the actual Make file (buildscript), and that the *.mk files are somehow inputs to that buildscript. So, for starters, if any of those assumptions are wrong, please begin by correcting me!
When I open makefile I see this:
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include src/subdir.mk
-include subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
# All Target
all: helloworld
# Tool invocations
helloworld: $(OBJS) $(USER_OBJS)
#echo 'Building target: $#'
#echo 'Invoking: Cross GCC Linker'
gcc -o "helloworld" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
# Other Targets
clean:
-$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) helloworld
-#echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets
Please note: I am not looking for someone to explain to me how Make works, I can RTFM for that ;-)
I am just trying to understand what it would take to compile, build and run helloworld from the command-line, outside of Eclipse. What command line invocations would I need to accomplish this, and why? Once I see that, combined with perusing Make docs, I should be able to fill in the gaps and understand everything that is going on.
That depends a bit on the paths that Eclipse generates in the files source.mk and objects.mk but most likely you need to cd into the Debug folder.
Inside of that, you can then run make all to compile the project.
If Eclipse generated absolute paths, you can use make -f .../path/to/helloworld/Debug/makefile all from anywhere.
The *.o files are the object file(s) created by compilation. these files are typically build by a command like:
Gcc -ansi -Wall -pedantic -c helloworld.c -o helloworld.o
(apologies foe capitalization of gcc, my iPad insists on correct my typing)
The *.exe is the actual executable, which may or may not contain the library functions. This depends on static versus dynamic linking. The executable is created typically by:
Gcc helloworld.o -o helloworld.exe
The *.d files are dependency files, built by gcc attempting to determine dependencies between files, typically built with the following command
MAKEDEPEND = gcc -M $(CPPFLAGS) -o $*.d $<
(Rule taken from make online documentation).
So,to answer your final question, to compile from the command line, a command like:
Foo gcc -ansi -WAll -pedantic helloworld.c -o helloworld.exe
Should do the trick for you. Note, the flags to the compiler are the minimum that I like to use, you will probably have a different set of switches.
Hopes this help,
T

makefile prerequisite appears older then target even if it was built afterwards

I am trying to add more then one file created in different directories to a static library but apparently it does not work as expected.
My makefile structure is something like this:
./src/drv/platform/AVR/
- hal
- hw
--- spi
--- uart
In hal I define a library name in $(LIB_TARGET) named libHal and all the *.o files should be archived in that library.
In hw I define another library name in $(LIB_TARGET) named libHw and all *.o files in hw/spi and hw/uart should go in that library: first the library libHw is created with the object files in hw/spi and they are never missed, then the objects in hw/uart are created and should be added to libHw.
In each subdirectory a generic makefile with suffix rules is ran that creates the object files and then should add each *.o to the library. At the end of the run I should have in another library directory(as in another location) 2 libs, libHal and libHw, libHal contains everything in hal, libHw everything in hw.
In this case the directory hw does not have any source files and looks like this:
SUBDIRS:= spi uart
LIB_TARGET = libHw.a
.PHONY: $(SUBDIRS) clean all
default: all
$(SUBDIRS)::
$(MAKE) -C $# $(MAKECMDGOALS)
all clean : $(SUBDIRS)
Each of the uart and spi subdirs hold something like this:
include $(TGT_BASE)/make/generic.mk
SRCS := uart.c
include $(TGT_BASE)/make/rules.mk
The file generic.mk only holds generic platform definitions.
The code for the generic makefile rules.mk with all the suffix rules.
.PHONY : all clean
OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
LIB_TARGETT = $(LIB_DIR)/$(LIB_TARGET)
### Archive into a library file (.a)
$(LIB_DIR)/%.a: $(OBJS)
#echo $(MSG_L)
#echo 'Adding $^ to library $#'
$(AR) $(ARFLAGS) $# $^
#echo $(MSG_L)
### rule for c files
%.o: %.c
#echo $(MSG_C)
$(CC) -c $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $< -o $#
#echo $(MSG_C)
### make dependencies
%.d: %.c
#echo $(MSG_D)
$(CC) -E -MM $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $(CURDIR)/$< > $#
#echo $(MSG_D)
all: $(DEPS) $(OBJS) $(LIB_TARGETT)
clean:
$(RM) -rf *.o *.d .depend
The makefile that exists in most
Now the problem is that sometimes some of the *.o files in hw/uart are not added to the library defined in hw. Running make in debug reveals that make itself considers the prerequisites for the library to be older then the last access to the library so they are missed.
Found an implicit rule for 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Pruning file 'uart.o'.
Finished prerequisites of target file 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Prerequisite 'uart.o' is older than target 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
To explain better how this goes when it works here is an example
make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror -Os -mmcu=atmega328p -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
------- make Lib -------
Adding uart.o to library F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/li
bHw.a
avr-ar rcs F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a uart.o
------- make Lib -------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'
And here is an example if it when it is not working
make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror -Os -mmcu=atmega328p -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'
I am using make 3.82.90 and Windows 7.
So any idea how I can force make to not miss those objects? Or to see their real time of creation and properly add them to the library? Remember, sometimes they are added, but sometimes they are not.
Thank you.
When you say it always works when you run it with make all --debug=a it always works: which part of that matters? If you run make all does it always work? Or if you run make --debug=a does it always work? Or do you have to use both to make it always work?
Since you're not showing all the makefile, we can't say much. For example, how are you setting the value of OBJS? Where and how do you define the rules that build object files (or are you using make's built-in rules for that)? That information is critical. It looks like what's happening is that make is asking you to build one file but your rules build a different file, so make sees that the file it expects was not actually updated and doesn't do anything.
Also, it's very confusing that in your overview you talk about things like dir1, dir2, dir2.1, etc. but then in the error output you provide completely different paths. We can't determine how the "real" pathnames in your example match up with the pseudo-paths in your overview.
Please either use real paths everywhere, or edit your example output to use the pseudo-paths, so we can see which paths are doing what.

Does order of linker flags matter when running linking step in C++?

My original question is below, but it evolved to the following related question: is there anything wrong with putting linker flags after the objects in the linker statement?
When I build in Eclipse, the following linking statement is run:
g++ -fopenmp -lconfig++ -o "pc2" ./main.o ./sampling.o ./simulation.o
which is incorrect, because lconfig++ must follow, not precede, the object file listing. So, I modified the makefile, which was automatically generated by Eclipse based on the project settings. Specifically, I changed this portion of the makefile
# Tool invocations
pc2: $(OBJS) $(USER_OBJS)
#echo 'Building target: $#'
#echo 'Invoking: GCC C++ Linker'
g++ -fopenmp -lconfig++ -o "pc2" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
to be as follows:
# Tool invocations
pc2: $(OBJS) $(USER_OBJS)
#echo 'Building target: $#'
#echo 'Invoking: GCC C++ Linker'
g++ -o "pc2" $(OBJS) $(USER_OBJS) $(LIBS) -fopenmp -lconfig++
#echo 'Finished building target: $#'
#echo ' '
Then, after modifying that 1 line of the makefile, I entered
make clean all -C release
at the command line, which produced the following correct linking statement:
g++ -o "pc2" ./main.o ./sampling.o ./simulation.o -fopenmp -lconfig++
Therefore, I know how to fix the makefile so that the build process is correct.
What I do not know is how to configure Eclipse so that the makefile it generates places the linker flags (or "options"?) at the correct location.
You've answered your own question: yes, the order of objects and libraries on the link line does matter.
is there any reason why I might need linker flags to precede the object files?
There may well exist such linker flags. For example --start-group GNU-ld linker options must (obviously) precede the library group it starts. The --start-lib Gold linker option must (obviously) precede the objects that form a library, etc.
I discovered that I could move ${FLAGS} in settings
You likely have included -lconfig++ in the ${FLAGS} somewhere in Eclipse, and that's likely a mistake -- the -lconfig++ is not a linker flag (even though it looks like one), it's a library specification, and should probably be included in ${LIBS} or some such.

Using make for cross platform compilation

I am currently developing a C project under Linux and Win32. The 'deliverable' is a shared library, and all the development is done under Linux with the GNU tool chain. I am using a Makefile to compile the shared library.
Every now and then I have to build a .dll under Win32 from the same src.
I've installed MinGW on the Win32 box such that I can use make and get far fewer complaints from the compiler (in comparison to MSVC). I'm at a stage where the src code compiles on both platforms
But the Linux Makefile and Win32 Makefile are different. I'm curious as how to best handle this - should I:
have 2 makefiles, e.g. Makefile for linux and Makefile.WIN32 and then run make -f Makefile.WIN32 on the Windows box
Should I make a different target in a single Makefile and do something like make WIN32 on the Windows box
Should I ditch make and use CMake (is the juice worth the squeeze for such a simple project, i.e. 1 shared library)
Use a single make file and put the platform-specifics in conditionals, eg
ifeq ($(OS),Windows_NT)
DLLEXT := .dll
else
DLLEXT := .so
endif
DLL := libfoo$(DLLEXT)
lib : $(DLL)
I use UNAME := $(shell uname) within my Makefile to detect the platform (Linux or MS-Windows).
I provide below a complete example based on make and gcc to build a shared library: *.so or *.dll depending on the platform.
The example is basic/simple/stupid to be more understandable :-)
To use make and gcc on MS-Windows, Cygwin or MinGW can be installed.
The example uses five files:
├── app
│ └── Makefile
│ └── main.c
└── lib
└── Makefile
└── hello.h
└── hello.c
The Makefiles
app/Makefile
app.exe: main.o
gcc -o $# $^ -L../lib -lhello
# '-o $#' => output file => $# = the target file (app.exe)
# ' $^' => no options => Link all depended files
# => $^ = main.o and other if any
# '-L../lib' => look for libraries in directory ../lib
# '-lhello => use shared library hello (libhello.so or hello.dll)
%.o: %.c
gcc -o $# -c $< -I ../lib
# '-o $#' => output file => $# = the target file (main.o)
# '-c $<' => COMPILE the first depended file (main.cpp)
# '-I ../lib' => look for headers (*.h) in directory ../lib
clean:
rm -f *.o *.so *.dll *.exe
lib/Makefile
UNAME := $(shell uname)
ifeq ($(UNAME), Linux)
TARGET = libhello.so
else
TARGET = hello.dll
endif
$(TARGET): hello.o
gcc -o $# $^ -shared
# '-o $#' => output file => $# = libhello.so or hello.dll
# ' $^' => no options => Link all depended files => $^ = hello.o
# '-shared' => generate shared library
%.o: %.c
gcc -o $# -c $< -fPIC
# '-o $#' => output file => $# = the target file (main.o)
# '-c $<' => compile the first depended file (main.cpp)
# '-fPIC' => Position-Independent Code (required for shared lib)
clean:
rm -f *.o *.so *.dll *.exe
The source code
app/main.c
#include "hello.h" //hello()
#include <stdio.h> //puts()
int main()
{
const char* str = hello();
puts(str);
}
lib/hello.h
#ifndef __HELLO_H__
#define __HELLO_H__
const char* hello();
#endif
lib/hello.c
#include "hello.h"
const char* hello()
{
return "hello";
}
The build
Fix the copy-paste of Makefiles (replace leading spaces by tabulation).
> sed -i 's/^ */\t/' */Makefile
The make command is the same on both platforms. The given output is for MS-Windows (unnecessary lines removed).
> cd lib
> make clean
> make
gcc -o hello.o -c hello.c -fPIC
gcc -o hello.dll hello.o -shared
> cd ../app
> make clean
> make
gcc -o main.o -c main.c -I ../lib
gcc -o app.exe main.o -L../lib -lhello
The run
The application requires to know where is the shared library.
On MS-Windows, the simple/basic/stupid way is to copy the library where the application is:
> cp -v lib/hello.dll app
`lib/hello.dll' -> `app/hello.dll'
On Linux, use the LD_LIBRARY_PATH environment variable:
> export LD_LIBRARY_PATH=lib
The run command line and output are the same on both platforms:
> app/app.exe
hello
As somebody who has used both autotools and CMake, I would recommend using CMake over rolling your own Makefiles and using autotools. CMake has so many useful, easy to use benefits, even if it is a simple project. For example, CMake will create an NSIS installer, manage production vs. debug compilation and has a nice testing framework. The one knock I had was that it was kind of hard to find real examples of how to use it. So much open source software uses autotools that realworld examples for it are easy to find. However, if you download the CMake source, there are lots of examples in the Example directory and Test directory.
In other words, the Juice is worth the squeeze.
I had a similar issue a few years back, and found that cmake is much easier for cross-platform compilation AND will use whatever compiler is native for that system. Syntax is clearer and abstracts details that are unnecessary for the most part (sometimes that got in the way, but usually there was a way around it)
As a primary advice, I suggest using libtool, autoconf and automake; they make cross-compilation very easy, and much easier than CMake.
If you are going the hand-crafted route, I would suggest going with different targets. Switching between makefiles tends to hide otherwise obvious errors in Makefiles, e.g. duplicately used objects with different rules. Example: The object foo.o is compiled for the DLL target and for the .so target, but with different flags. If someone switches Makefiles, the existing .o file with wrong flags is used, breaking the build. If you are using one Makefile, this will become obvious through rule conflicts.
If you are willing to use MSYS2 on Windows you might get it to run without
making any changes at all compared to your code written for Linux.
This goes for your C/C++ source code as well as for your makefile.(!)
I have been developing code for Linux exclusively. When I tried running it
inside an MSYS2 terminal, the code turned out to work just fine, and
produced a Windows binary executable. I was positively surprised.
You will need to know how to install and use MSYS2, of course. For example,
to install make and g++, in an MSYS2 terminal run the commands:
yes | pacman -Syu msys/make
yes | pacman -Syu gcc
If you want to find out where in Windows g++ has been installed, you can run
where g++ in the MSYS2 terminal.
References:
https://www.msys2.org/wiki/MSYS2-installation/
https://github.com/msys2/MSYS2-packages/issues/293

Compile wcecompat to a dll

I am using wcecompat to bridge the gap between WinCE SDK and OpenSSL. Due to LGPL license issue, I want to compile it to a dynamically linked library. Here is part of the makefile (full file is at https://github.com/mauricek/wcecompat/blob/master/makefile). My question is, how to modify it to build a dll instead of a static lib?
all: lib\wcecompat.lib lib\wcecompatex.lib
echo $(OBJS)
obj:
#md obj 2> NUL
lib:
#md lib 2> NUL
$(OBJS): makefile obj
lib\wcecompat.lib: lib $(OBJS) makefile
#lib /nologo /out:lib\wcecompat.lib $(LFLAGS) $(OBJS)
lib\wcecompatex.lib: lib $(OBJS) makefile
#lib /nologo /out:lib\wcecompatex.lib $(OB
JS)
Use link (i.e. link.exe) instead of lib for the two targets:
lib\wcecompat.lib: lib $(OBJS) makefile
#lib /nologo /out:lib\wcecompat.lib $(LFLAGS) $(OBJS)
lib\wcecompatex.lib: lib $(OBJS) makefile
#lib /nologo /out:lib\wcecompatex.lib $(OBJS)
... and rename the targets to wcecompat.dll and wcecompatex.dll respectively.
However, this will indeed only help you to build the DLL, it does not cover any modifications to export the functions you may need from that DLL. Also remember that DLLs with Code have a DllMain function as entry point (though it's not exported as such).

Resources