Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Switched to Visual Studio Code in an effort to understand C/C++ dev tools and to stop relying on IDEs. I try to use Makefiles for this purpose because it allows to run compilation via command line on a target device (no GUI == no IDE). So far I've managed to make a generic Makefile that compiles all .cpp files to corresponding .o files and then links it all together. It works for small projects that store all sources in a single directory. Now I must port my working Xcode project.
The problem is that the source files are stored in a directory tree (no single directory) and may be both C and C++. Some files have similar filenames but reside in different folder. From C++ perspective it means classes the have same name, but different namespaces. Various IDEs handle this easily but Makefile gives me all sorts of problems cause I am not yet a make guru.
I've tried to create Makefiles in each directory (I failed), but then I read that is considered a bad approach so I switched to a single Makefile approach. Some say I should switch to CMake but I think that it is pointless without understanding the Makefile creation first because CMake would eventually create one. It would also allow to build and install on devices without CMake and other cool tools (if, for example, there is no Internet connection to download CMake).
Here is a basic idea:
- project-name/
- application/
- core/
- loader.hpp
- loader.cpp
- ...
- loader.hpp
- loader.cpp
- ...
- hardware/
- loader.hpp
- loader.cpp
- ...
- some-c-library
- library.h
- library.c
- ...
- main.cpp
- project-name.xcodeproj
- Makefile
TR&DL: Unable to make complicated Makefile. GNU manual is hard to understand and online blogs/tutorials mostly touch only basic stuff.
I'm really not sure you need to be overly complicated. Sure, you could have the Makefile hunt down your directory tree for every C and C++ file, but what if you've added a new file that you don't want compiled just yet?
You can make things easier without being too complicated though. Assign the list of source files to variables - that way you can refer to them whenever you need them.
CPPSOURCES=hardware/loader.cpp application/core/loader.cpp main.cpp
CSOURCES=some-c-library/library.c
Then you convert those filenames into object filenames - this is just doing a replace of .cpp with .o etc...
CPPOBJS=$(CPPSOURCES:.cpp=.o)
COBJS=$(CSOURCES:.c=.o)
And there are standard variables that make uses for specifying what flags to pass to the C++ and C compilers
CXXFLAGS-g
CFLAGS-g
Then you have a rule to build your project. $# is the name of the thing the rule is building (ie "myproject") and $^ is the list of dependencies.
myproject: $(COBJS) $(CPPOBJS)
$(CXX) $(CXXFLAGS) -o $# $^
Make comes with a bunch of default rules so that it already knows that if you ask it to build "some/where/deep/in/my/project/somefile.o" that it's looking for "some/where/deep/in/my/project/somefile.cpp" for example.
You could add a rule to delete all the object files - this is why using variables comes is handy
clean:
rm $(COBJS) $(CXXOBJS)
The only other thing you'll need to worry about are dependencies, like the below example which tells make that it needs to build "hardware/loader.o" whenever "hardware/loader.hpp" or "application/core/loader.hpp" are newer.
hardware/loader.o: hardware/loader.hpp application/core/loader.hpp
This is probably the one area where you want to investigate automatically generation as it's very easy to miss out a dependency and then it won't pick up any changes in the headers. As noted in the comments, gcc/g++ can generate files with them in for you when you build the code using the -M command line options which you can use the include directive in the Makefile to add them.
Related
A question regarding "sentinels" in included make files.
I've inherited a project with a hierarchy of gmake projects, which uses make recursively. Due to the structure of the project, some files are included multiple times (once for each use of recursive gmake). These files are nothing fancy. Just variable definitions with some very basic if-logic. No recipes or dependencies. No nested includes.
The multiple-inclusion creates maintenance headaches. E.g. One can't use += in these files. I'd like to block multiple inclusions.
Putting a sentinel in the included files is the obvious solution, e.g.
ifeq ($(FOO_INCLUDED),)
FOO_INCLUDED=yes
else
# everything else
endif
But .... adding such a sentinel makes some recipes disappear in some sub-projects. E.g. a "build" target might disappear, while the "clean" target for the same sub-project doesn't. Make reports no egregious errors - it does attempt to run things. It just reports a missing target.
So the question is ... what could cause recipes being lost?
Restructuring to avoid the multiple includes is unfortunately not an option. Each sub-project is supposed to be buildable from either it's own folder (cd sub-project ; gmake build), or from the root folder (cd proj-root ; gmake subproject_build)
I've got the following piece of script in my CMake file:
CONFIGURE_FILE(
${CMAKE_CURRENT_SOURCE_DIR}/version.hpp.cmake
${CMAKE_CURRENT_SOURCE_DIR}/version.hpp
)
But it's only run after executing cmake, not make. Is it possible to create the version.hpp file after each make?
Here is the content of version.hpp.cmake:
#ifndef _VERSION_HPP_
#define _VERSION_HPP_
#define MAJOR_VERSION "${MAJOR}"
#define MINOR_VERSION "${MINOR}"
#define PATCH_VERSION "${PATCH}"
#define RELEASE_VERSION "${RELEASE}"
#endif //_VERSION_HPP_
The MAJOR, MINOR, PATCH and RELEASE variables have been defined in the CMakeLists.txt file.
P.S. This post is apparently related to my question, but I can't get a grasp of it.
The problem is that configure_file is supposed to run at configure time, that is when you run cmake, instead of compile time, which is when you run make. There is no easy way around this.
The problem is that the information written by configure_file is dependent on variables from the CMake build environment. Changes to those variables cannot be detected without running CMake again. If you have that information mirrored somewhere else, you can use a custom command to extract it and perform the code generation for you, as Peter's answer suggested.
The approach suggested in the post from the CMake mailing list that you linked in your answer is based on a two-phase CMake run: The outer CMake project (which is run only once) adds a custom build step for building the inner CMake project (which is then run with every make) where the configure_file is performed. The underlying idea is the same as with Peter's answer, only instead of a Python script you use a CMake script for generating the file.
My personal recommendation: For a simple problem as a version header, I would not bother with such a complicated approach. Simply generate the file to your BINARY_DIR (not to your project dir, as you currently do! you want to retain the ability to do several out-of-source builds from the same source) and assume that it will be there for compilation. If a user is brave enough to mess with the generated files there, they can be expected to re-run CMake on their own.
So I accidentally stumbled across this, I know it is probably too late, but calling configure is possible an exactly how I do this with mercurial versions.
The trick requires a lot of different tools, and I don't have time to formulate into a good answer atm, but ask questions and I'll fill it in when I have time.
tool 1: calling exec_program to extract the revision information (this is really easy with mercurial)
exec_program(hg ${PROJECT_SOURCE_DIR} ARGS "id" "-i" OUTPUT_VARIABLE OUTPUT_VARIABLE ${PROJECT_NAME}_HG_HASH_CODE)
I'm probably doing something more complicated than you care about here, but the essential bit is hg which you'll replace with whatever version control you are using, ${PROJECT_SOURCE_DIR} which you'll set to whatever executing directory you want, and fill in the custom args.
I put all of the version extraction into a single macro (ReadProjectRevisionStatus()).
The next step is to make a an entirely different CMake file that calls ReadProjectRevisionStatus() and then CONFIGURE_FILE. This file will assume that all the correct values are set when you come into it. In my case, I store the location of this file into ${CONFIG_FILE_LOC}.
The final step is to add a custom target that will call this script. For example:
ADD_CUSTOM_TARGET(${PROJECT_NAME}_HG_VERSION_CONFIG
COMMAND ${CMAKE_COMMAND}
ARGS -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
-DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}
-DPROJECT_NAME=${PROJECT_NAME}
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
"-D${PROJECT_NAME}_HG_CONFIG_FILE_IN=\"${${PROJECT_NAME}_HG_CONFIG_FILE_IN}\""
"-D${PROJECT_NAME}_HG_CONFIG_FILE_OUT=\"${${PROJECT_NAME}_HG_CONFIG_FILE_OUT}\""
${ARGN}
-P ${CONFIG_FILE_LOC})
One of the beauties of doing it this way is that custom target call can still be called outside of a cmake build system, which I've done on a couple of projects, which a bash call similar to:
cmake -D PROJECT_SOURCE_DIR=$sourcedir -DPROJECT_BINARY_DIR=$sourcedir -DPROJECT_NAME=uControl -DCMAKE_MODULE_PATH=$sourcedir -DuControl_HG_CONFIG_FILE_IN=$sourcedir/tsi_software_version.h.in -DuControl_HG_CONFIG_FILE_OUT=$sourcedir/tsi_software_version.h -P $sourcedir/ConfigureHGVersion.cmake
One possibity is to generate version.hpp from Python and use ADD_CUSTOM_TARGET
... find python ...
ADD_CUSTOM_TARGET(gen_version ALL ${PYTHON_EXECUTABLE} gen_version.py)
SET_SOURCE_FILES_PROPERTIES(version.hpp PROPERTIES GENERATED 1)
... link gen_version to your library/executable ...
I am getting familiar myself to LLVM, and my goal is to implement a back-end for my custom processor.
Before I jump into my back-end implementation, I first try to learn how a build procedure works, so I first copy lib/Target/MSP430 to lib/Target/myproc, and build llvm targeting "myproc" (even though it actually is a back-end for MSP430, I did this just to learn how I can add a new target to LLVM).
When I configure/make llvm, I got the following error message.
...
/bin/cp: cannot stat `/mydir/build/lib/Target/myproc/Debug+Asserts/MSP430GenRegisterInfo.inc.tmp': No such file or directory
...
I checked /lib/Target/myproc, and saw there was only one file, Makefile, copied from /lib/Target/myproc.
Here is what I have done before I configure and make.
In my LLVM source directory, copy lib/Target/MSP430 to lib/Target/myproc.
Modify configure and projects/sample/configure to add "myproc".
Go to lib/Target/myproc and change "MSP430" to "myproc" in MSP430.td, LLVMBuild.txt, and Makefile (I also modify the files in subdirectories).
As the LLVM compile works for other targets on my machine, I believe it's not the problem of machine of tools that I am using, but the problem of my modification.
Am I missing something? Are there any further modifications that I am supposed to make?
There's a decent tutorial for writing backends here:
http://llvm.org/docs/WritingAnLLVMBackend.html
There's also this tutorial from a dev meeting:
http://llvm.org/devmtg/2012-04-12/Slides/Workshops/Anton_Korobeynikov.pdf
*GenRegisterInfo.inc comes from running tblgen on the target .td file. The .inc output file name depends on what the .td files are named in the myproc/ target directory.
It would be helpful to see more of your make log but my guess is that you're getting a tblgen error when processing .td files in myproc/. That tblgen error is the real problem you need to diagnose and address.
I am autotoolizing a library project, and this project has some example programs. I want the example programs to be distributed in the dist, but not installed.
Currently the demo programs are organized like thus:
src/*.cpp (library source)
include/*.h (library headers)
demos/demo.cpp (example program)
demos/RunDemo (script to run demo)
It is important that RunDemo be runnable after building the software, without requiring the "install" step.
So far I have been able to build the "demo" exectuable using a noinst_PROGRAMS target. However, after make in a VPATH build, the following is available:
build/src/.libs/libxxx.so (etc..)
build/demos/demo
As you can see, the RunDemo script needed to execute "demo" is not copied to the $(builddir). I have tried a few things, e.g., adding RunDemo to dist_noinst_SCRIPTS, as well as adding my own copy targets and trying to hook all.. no matter what I try, I always get the output,
$ make RunDemo
make: Nothing to be done for `../../../projects/demo/RunDemo'.
I seem to be unable to create a target in the builddir that says "if this file is not in the builddir, copy it from the srcdir."
Is this possible with automake?
You can make files accessible in the build tree after the ./configure step using the AC_CONFIG_LINKS macro (provided with autoconf) in your configure.ac script. It will create a symbolic link if possible, otherwise it will copy the file.
In your case it would look like
AC_CONFIG_LINKS([demos/RunDemo:demos/RunDemo])
From the autoconf manual:
Macro: AC_CONFIG_LINKS (dest:source..., [cmds], [init-cmds])
Make AC_OUTPUT link each of the existing files source to the
corresponding link name dest. Makes a symbolic link if possible,
otherwise a hard link if possible, otherwise a copy. The dest and
source names should be relative to the top level source or build
directory
Using dist_noinst_SCRIPTS is still necessary for the file to be distributed.
I need some help debugging a Makefile system. I have a rather huge Makefile dependency tree, actually the Android source makefile system.
At some point the build fails because a file is missing:
/bin/bash: out/host/linux-x86/bin/mkfs.ubifs: No such file or directory
The file mkfs.ubifs is supposed to be "build" during the make process, and indeed it works if I do:
make out/host/linux-x86/bin/mkfs.ubifs
The mkfs.ubifs is build, and everything is working, until I again clean everything and build from the beginning.
This indicates to me, that there is a missing dependency somewhere. So my question is, how do I go about debugging this? How do I discover exactly which target is missing a dependency? What options can I provide for make which will give me clues as to where the error is?
Any other suggestions will also be appreciated. Thanks. :)
Update
Using make -d provides quite a lot of output. How exactly do I determine from which make target (sourcefile and line) and error occurred?
Problem solved. It seems make -p was the most useful way to debug this problem:
-p, --print-data-base
Print the data base (rules and variable values) that results from
reading the makefiles; then execute as usual or as otherwise spec-
ified. This also prints the version information given by the -v
switch (see below). To print the data base without trying to
remake any files, use make -p -f/dev/null.
From that output it is relatively easy to determine which target was failing, and what dependency that should be included.
There is a discrepancy between target's prerequisites and its commands, that is, a dependency is not specified for a target. I don't think you can debug that using make means because make can't tell you that a dependency is missing.
However, you can try invoking make with -d switch. That is going to tell you which target it tries to build when it hits the missing file. The next step would be to find the rule for that target in the makefile and add the missing dependency.