Seperate build directory and include directory in Jam - build

I'd like to switch to using Jam as my build system. Currently, I have a src, include and build directories and I'm wondering how I can get Jam to put object files in the build directory and search for include files in the include directory.

Good for you for using Jam! I think you'll find it a lot easier than makefiles, once you get past a few of its oddities.
What you are asking about is a setup I have often used. At the top level, I have three directories: src, inc, and build. There is also a file called Jamfile:
# top-level Jamfile
SubDir . ;
SubInclude src ;
SubInclude build ;
The SubDir line establishes the location of this file within the directory structure, and seems to be necessary for Jam to work. (I think Jam could have been designed to not need it, but there it is, so be it.) The SubInclude lines tell Jam to include two subdirectories. The inc subdirectory is not included because there is nothing there that needs to be compiled directly; all its contents will be included by other files.
Within inc, I have a header file called header.h:
/* header.h */
#define MESSAGE "Hello world!"
Within src, I have the source of the main program, main.c:
/* main.c */
#include "header.h"
#include <stdio.h>
int main(int argc, char** argv)
{
printf("%s\n", MESSAGE);
return 0;
}
Also within src is another Jamfile with these contents:
# src/Jamfile
SubDir .. src ;
HDRS += ../inc ;
Library helloworld : main.c ;
The SubDir line locates the Jamfile within the directory structure. The HDRS line tells Jam where additional headers can be found (it will pass this on to the compiler when the time comes). Note the use of the += operator, which appends to an existing variable. The Library line tells Jam to build a library out of main.c (yes, a library with a main() is a little weird, but OK on a small project like this).
Within build is a single Jamfile:
# build/Jamfile
SubDir .. build ;
Main helloworld ;
LinkLibraries helloworld : helloworld ;
SubInclude .. src ;
The SubDir line locates the Jamfile within the directory structure. The Main line tells Jam to build an executable called helloworld. Note that it has no source file dependencies. If it did, it would look like Main hello world : foo.c ;. The LinkLibraries line tells Jam to link the helloworld executable with a library, also called helloworld. It is OK in this case that the executable and library have the same name, but in a real program you might want to give them different (and better) names. The SubInclude line tells Jam to look in the src directory for more code to build. This is how the dependency between the executable and the library gets resolved. It is important that this line come last.
Now, if you navigate to the build directory and execute the jam command, Jam will build a helloworld.a file in src, and link it into a helloworld executable in build.
Because all the code in src is being compiled into a library, there are no .o files left over. They are all stored inside the .a file, which is an archive, after all. If you have additional source files in build (like the hypothetical foo.c mentioned above), then you would have .o files left over in the build directory after compiling.
Good luck with all this. I learned most of what I know about Jam from the Perforce website and through experimentation. The main Perforce page for Jam is here.

Related

RTOS SDK including custom library with Make

I am working on a project where I have to include my library into an ESP8266 project. The library is build with CMake and works great on an ESP32. The RTOS SDK uses Make to compile and link the project. Therefore, I have to add Makefiles to the project to make it work.
I followed the manual where they explained that in the Makefile I include the following line:
EXTRA_COMPONENT_DIRS := AMI_SP_LIB (Name of my custom library)
Then it will look in this directory (including one layer deeper) for components (components.mk)
In a components.mk file I have to include the src directory and the inc directory. My file will look like this:
COMPONENT_ADD_INCLUDEDIRS += ./inc
COMPONENT_SRCDIRS := ./src
My (partial) folder structure looks like this:
The error I am getting is that it can't find the include I did in a header file from a different subfolder. The error:
fatal error: Nanopb/inc/pb.h: No such file or directory
#include <Nanopb/inc/pb.h>
This is strange to me since I include the include path for the component. Which I think means that it should be able to find it with: #include <> In addition, the CMake is able to find the components with this type of include.
Any clue on how I should alter the makefiles to make it work?

CMake target_include_directories does not affect header files

My project is roughly structured like this:
├CMakeLists.txt
|
├───ExampleApp
| ├───CMakeLists.txt
| ├───header.hpp
| └───main.cpp
|
└───ExampleLibrary
├───CMakeLists.txt
├───mylib.hpp
└───mylib.cpp
In the root CMakeLists.txt I call
add_subdirectory(ExampleLibrary)
add_subdirectory(ExampleApp)
To build the library I call:
add_library(ExampleLibrary
mylib.hpp mylib.cpp
)
And finally, in the executable, I try to do:
add_executable(ExampleApp
header.hpp main.cpp
)
target_include_directories(ExampleApp
PRIVATE ${PROJECT_SOURCE_DIR}/ExampleLibrary
)
target_link_libraries(ExampleApp
Path/To/The/Binary/Directory
)
Now the build files generate just fine, and the project also builds with no errors. However, when I now try to include mylib.hpp in header.hpp, I get build errors because it can't find the file mylib.hpp. But I actually can include mylib.hpp in main.cpp and the project builds and compiles.
Am I missing something? I thought target_include_directories() works for both .cpp and .hpp files.
It seems like you may not have added the correct directory as an include directory for the ExampleApp. The PROJECT_SOURCE_DIR variable evaluates to the directory in which the last project() call was made in your CMake project. You have not shown where this is, but you could use the root directory of the CMake project to be sure it is correct; try using ${CMAKE_SOURCE_DIR}/ExampleLibrary in the target_include_directories call instead:
target_include_directories(ExampleApp
PRIVATE ${CMAKE_SOURCE_DIR}/ExampleLibrary
)
A couple more notes:
If you aren't using an IDE such as Visual Studio for compilation, there is no need to add header files to calls like add_library() and add_executable(). Doing this only ensures they are shown in an IDE.
Instead, specify directories within which the headers can be found, using target_include_directories(). In your case, it sounds like you should have both directories listed here.
To link the ExampleLibrary target to the executable, you can simply use the target name in target_link_libraries(). There is no need to list out the binary directory (unless you are linking other libraries from there).
So with this in mind, the ExampleApp CMake file could look something like this:
add_executable(ExampleApp
main.cpp
)
target_include_directories(ExampleApp PRIVATE
${PROJECT_SOURCE_DIR}/ExampleLibrary
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(ExampleApp PRIVATE
ExampleLibrary
)

CMake file for a C++ project

There is some CMake magic I don't understand. How should a CMakeLists.txt file look like for a small C++ project with directories like this:
.
├── bin
└── src
├── src
└── test
bin — directory for built program
src/src — directory for source
src/test — directory for tests
The tests will need to include files from src/src.
I'd like to manage all the operations from cmake, however at this moment I even can't cause cmake to compile file in src/c.cpp.
Any help, links are welcome.
Your CMake files should reside in the main source directory and its sub-directories. The easiest approach is to have one CMakeLists.txt in the src directory, which includes all files from src/src and src/test. A very minimalistic example could look like the following:
# CMakeLists.txt in src
project(myExample)
set(myExample_SOURCES
src/file1.cpp
src/main.cpp)
add_executable(myExecutable ${myExample_SOURCES})
set(myExample_test_SOURCES
src/file1.cpp
test/test_file2.cpp
test/test_main.cpp)
add_executable(myTestSuite ${myExample_test_SOURCES})
The output directory is normally not specified, because you can have different active
builds in parallel with
different options, e.g. you can have one build in debug mode -O0 -g, another one in release mode with -O2 -g flags and a third one in release mode with heavy optimization flags -O3. Every build resides in its own directory (e.g. build-debug, build-rel,
build-opt).
You should create the output directory (bin in your case) manually and call the cmake command inside this directory. As an argument you have to supply the path to the main CMakeLists.txt. In other words, just execute
cmake ../src
when you are inside bin. This will take all files from the src directory and put the output to the bin directory.
You can easily create a second output directory, say bin2, where you specify different build flags. The ccmake provides a very minimalistic GUI for that.
This helped me to start with cmake examples.html

How to compile multiple files in ROOT

I wrote a C++ program (with a main.cpp, and various header and implementation files) that compiles fine under g++. Now I am trying to compile it in Cern's ROOT library, but I do not know how to, since the only way I know how to compile files in ROOT is by using .L main.cpp.
How can I include multiple files in ROOT?
The most reliable way to use ROOT (at least historically and currently) is to ignore the interpreter other than for the simplest explorations and explicitly compile your C++ programs against the ROOT libraries. For example, use
g++ MySource.cc `root-config --libs --cflags` -o foo
to compile an executable "foo" from a single source file. For more info on that helper script run "root-config --help".
Multi-file programs/libraries are nothing special provided that you supply the required args to point at the ROOT libraries and headers (and that the libs are available in LD_LIBRARY_PATH at runtime.) Standard C++ guides will explain that step if needed. You can safely put this into a makefile, too.
For my money this is both easier and more reliable than using the .L etc. commands in the CINT interpreter. Last time I tried, ACLiC was actually compiling against a temporary (and mangled) version of the specified source file, so any error messages from the compiler were pretty much useless!
I use CMake to compile my ROOT-based projects.
If you have a project directory proj/ and it contains src/ and bin/, you'll need 3 CMakeList.txt files, one in each directory.
A simple example CMakeList.txt in the main project directory:
cmake_minimum_required(VERSION 2.6)
project (SOME_PROJ_NAME)
add_subdirectory(src)
add_subdirectory(bin)
src/ directory is where you keep your .h and .cxx proj. library files. Example CMakeList.txt file:
# get all the *.cxx filenames, to compile them into a lib
file(GLOB SOME_PROJ_LIB_SRCS "${PROJECT_SOURCE_DIR}/src/*.cxx")
# include ROOT library and include files
include_directories(/path/to/root/dir/include/dir)
link_directories(/path/to/root/dir/lib/dir)
# and compile src into a library
add_library(Proj_lib_name ${SOME_PROJ_LIB_SRCS})
# here, list the ROOT libraries you require
target_link_libraries(Proj_lib_name dl Core Cint RIO Net Hist Graf Graf3d Gpad Tree Rint Postscript Matrix Physics MathCore Thread Gui pthread m)
bin/ directory is where you keep your app .cxx files and it has a CMakeList.txt file:
include_directories(${PROJECT_SOURCE_DIR}/src)
link_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(/path/to/root/dir/include/dir)
link_directories(/path/to/root/dir/lib/dir)
add_executable(example_app.exe example_app.cxx)
target_link_libraries(example_app.exe Proj_lib_name dl Core Cint RIO Net Hist Graf Graf3d Gpad Tree Rint Postscript Matrix Physics MathCore Thread Gui pthread m)
Finally, to compile ROOT-based code with CMake, out of source, you create a "build" dir in your top level project dir, so that your dir structure looks like this:
proj/
bin/
build/
src/
Then
cd build
cmake ..
Your binaries will be located in build/bin/ directory
Hope this helps.
It appears that I would simply .L <filename> for each file I want, since .L tells ROOT to "load the contents of file in memory." Though now I am not too sure which order to load the files in, as they are giving me errors.

Define cross directory dependencies in Jam

After many years of using make, I've just started using jam (actually ftjam) for my projects.
In my project workspaces, I have two directories:
src where I build executables and libraries
test where my test programs are
I'm trying to set up a dependency on test programs so that each time I compile them, the libraries will be recompiled as well (if they need to).
Any suggestion on how to do it?
Ok this seems to be not an as easy question as I thought so I worked out a solution on my own. It uses a script to achieve the end result so I still hope that a Jam guru will have a jam-only solution.
Create a Jamrules in the root directory of the project with the common definitions.
Create a Jamfile in the root directory of the project with the following content:
SubDir . ;
SubInclude . src ;
SubInclude . test ;
Create a Jamfile in the src directory
SubDir .. src ;
Library mylib : mylib.c ;
Create a Jamfile in the test directory
SubDir .. test ;
Main mytest : mytest.c ;
Depends mytest : mylib$(SUFLIB) ;
With this setting, as long as I am in the root directory, whenever I try to build mytest the library will also be recompiled (if needed). I found an old message on the jammer mailing list describing it.
Alas this doesn't work if I'm in the test subdirectory since jam can only look down into subdirectories.
So, I created a simple script called jmk and put it together with the jam executable (so that both are in the path):
if [ "$JMKROOT" = "" ] ; then
JMKROOT=`pwd`
export JMKROOT
fi
cd $JMKROOT
jam $*
and I set the JMKROOT environment variable to the root of my project.
For when I compile in a Windows shell (that's why I want to use Jam) I simply use this small jmk.bat batch file:
#echo off
if "%JMKROOT%" EQU "" set JMKROOT=%CD%
set OLDCD=%CD%
cd %JMKROOT%
jam %1 %2 %3 %4 %5 %6 %7 %8 %9
cd %OLDCD%
I'm using Jam in one of my projects, and I am encountering your very situation. I have my executable programs in the bin subdirectory, and my static libraries are kept in the lib subdirectory.
In my top-level Jamfile, I type in SubDir TOP ;. This initializes the $(TOP) variable to point to the directory containing this Jamfile. I then add lines such as SubInclude TOP bin llvm-tblgen and SubInclude TOP lib Support, which adds the contents of the Jamfiles in bin/llvm-tblgen and lib/Support to the build.
In the Jamfile in bin/llvm-tblgen, I type in SubDir TOP bin llvm-tblgen ;. I do the same in the Jamfile in lib/Support, but I use SubDir TOP lib Support ; instead. The key when entering SubDir rules is to type in the names of each subdirectory from the TOP to the directory containing this Jamfile.
Then, when it is time to set the linkline of my executable target, I reference the support library like this: $(TOP)/lib/Support/libLLVMSupport.a. Jam expands this path into the location of libLLVMSupport.a, relative to where I run Jam, even if I cd into the bin/llvm-tblgen directory and run Jam manually from there.
This makes it very easy to manage large projects that contain cross-directory dependencies. This solution, unlike your earlier one, lets you run Jam directly. Hope it helps you!