-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
squash - commit of WIP on tutorial documents
- Loading branch information
Showing
2 changed files
with
409 additions
and
0 deletions.
There are no files selected for viewing
361 changes: 361 additions & 0 deletions
361
tribits/doc/tribits_tutorial/TribitsTutorialHelloWorld_0.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,361 @@ | ||
======================================= | ||
TriBITS Hello World Tutorial | ||
======================================= | ||
|
||
:Author: Roscoe A. Bartlett ([email protected]), Joe Frye ([email protected]) | ||
:Date: |date| | ||
:Version: .. include:: TribitsGitVersion.txt | ||
|
||
.. |date| date:: | ||
|
||
|
||
.. sectnum:: | ||
:depth: 2 | ||
|
||
.. Above, the depth of the TOC is set to just 2 because I don't want the | ||
.. TriBITS function/macro names to have section numbers appearing before them. | ||
.. Also, some of them are long and I don't want them to go off the page of the | ||
.. PDF document. | ||
.. Sections in this document use the underlines: | ||
.. | ||
.. Level-1 ================== | ||
.. Level-2 ------------------ | ||
.. Level-3 ++++++++++++++++++ | ||
.. Level-4 .................. | ||
.. contents:: | ||
|
||
The Simplest HelloWorld project | ||
=================================== | ||
This short tutorial will walk you through setting up a basic HelloWorld project | ||
built by TriBITS to intdroduce the basic concepts in TriBITS. To begin you | ||
will need cmake and TriBITS installed on your machine. You will also need a | ||
working c and c++ compiler. | ||
|
||
TriBITS projects have a specific structure ie a project is a collection of | ||
packages. For this example we will be creating a project that has just one | ||
package, the "HelloPackage" package. | ||
|
||
Initial Setup | ||
---------------- | ||
First lets create all the directories for our project. We will need a top level | ||
directory for the project which I will call tribits_hello_world. We need a | ||
directory for the "HelloPackage" package. We will also need a directory for the | ||
build which I call "build". Under the hello_package_dir also create the directories | ||
"camke" and "src":: | ||
|
||
tribits_hello_world/ | ||
tribits_hello_wolrd/build | ||
tribits_hello_world/hello_package_dir | ||
tribits_hello_world/hello_package_dir/cmake | ||
tribits_hello_world/hello_package_dir/src | ||
|
||
$ tree | ||
. | ||
└── tribits_hello_world | ||
├── build | ||
└── hello_package_dir | ||
├── cmake | ||
└── src | ||
|
||
Create a TriBITS package | ||
------------------------- | ||
The most basic TriBITS package needs to have 3 files. | ||
* a top level CMakeLists file | ||
* a source file | ||
* a file that track package dependencies | ||
|
||
First lets create the source file which is the classic HelloWorld.cpp. Just | ||
copy this to HelloWorld.cpp in the src directory:: | ||
|
||
#include <iostream> | ||
|
||
int main() | ||
{ | ||
std::cout << "Hello World!\n"; | ||
return 0; | ||
|
||
} | ||
|
||
Second lets create the package dependencies file which should be placed in the | ||
cmake directory. Copy the below text into a file called Dependencies.cmake:: | ||
|
||
TRIBITS_PACKAGE_DEFINE_DEPENDENCIES() | ||
|
||
In this case the package we are creating has no dependencies but we still need | ||
this file. The lack of arguments to the TRIBITS_PACKAGE_DEFINE_DEPENDENCIES() call | ||
reflects that this package does not have dependencies. The last and most interesting | ||
file we will create in the package directory is the CMakeLists.txt file. Copy the following | ||
into CMakeLists.txt:: | ||
|
||
TRIBITS_PACKAGE(HelloPackage) | ||
TRIBITS_ADD_EXECUTABLE(Hello-Executable-Name NOEXEPREFIX SOURCES src/HelloWorld.cpp INSTALLABLE) | ||
TRIBITS_PACKAGE_POSTPROCESS() | ||
|
||
|
||
**TRIBITS_PACKAGE(HelloPackage)** Sets this up a TriBITS package with the name "HelloPackage" | ||
|
||
**TRIBITS_ADD_EXECUTABLE(Hello-Executable-Name NOEXEPREFIX SOURCES src/HelloWorld.cpp INSTALLABLE)** tells | ||
TriBITS that we want to build an executable named "Hello-Executable-Name" from the source file src/HelloWorld.cpp. | ||
NOEXEPREFIX and INSTALLABLE are options to TRIBITS_ADD_EXECUTABLE() that I will not go into right now. | ||
|
||
**TRIBITS_PACKAGE_POSTPROCESS()** Must be at the end of any packages top level CMakeLists file | ||
|
||
**Say some stuff about Tribits packages (here) or at teh top of this section** | ||
|
||
Create a Tribits Project | ||
------------------------- | ||
Recall that a TriBITS project is made up of TriBITS packages. We have just defeined a package now we will create | ||
a project that consists of just that one package. In order to do this we are going to create 4 files in the top | ||
level directory and they are named: | ||
* CMakeLists.txt | ||
* PackageList.cmake | ||
* ProjectName.camke | ||
* TPLsList.cmake | ||
|
||
**TPLsList.camke** this file tells Tribits ablout TPLs needed for the project. In this case, the package does not | ||
depend on any TPLs so this file will be very simple. It should contain just the following single line:: | ||
|
||
TRIBITS_REPOSITORY_DEFINE_TPLS() | ||
|
||
**ProjectName.camke** this file sets the name of the project. Some other options can be specified in this file but we | ||
will just set the project name. It should contain the following:: | ||
SET(PROJECT_NAME TribitsHelloWorld) | ||
|
||
**PackageList.cmake** defeines which packages are in the project. We will just need to tell it the name and location | ||
of our one package:: | ||
|
||
TRIBITS_REPOSITORY_DEFINE_PACKAGES( | ||
HelloPackage hello_package_dir PT | ||
) | ||
|
||
**CMakeLists.txt** This is the most interesting file in this example. Here we will set a minimum cmake version, load some | ||
options, and tell cmake that this is a Tribits project. The CMakeLists.txt file should have the following contents:: | ||
|
||
# To be safe, define your minimum CMake version | ||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11 FATAL_ERROR) | ||
# Make CMake set WIN32 with CYGWIN for older CMake versions | ||
SET(CMAKE_LEGACY_CYGWIN_WIN32 1 CACHE BOOL "" FORCE) | ||
# Get PROJECT_NAME (must be in file for other parts of system) | ||
INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/ProjectName.cmake) | ||
# CMake requires that you declare the CMake project in the top-level file | ||
PROJECT(${PROJECT_NAME} NONE) | ||
|
||
# This needs to be set to the path to the installation of TriBITS on your machine | ||
SET(${PROJECT_NAME}_TRIBITS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tribits | ||
CACHE PATH "TriBITS base directory (default assumes in TriBITS source tree).") | ||
|
||
# Include the TriBITS system | ||
INCLUDE("${${PROJECT_NAME}_TRIBITS_DIR}/TriBITS.cmake") | ||
# MPI and Fortran are enabled by defualt, turn them off for this project | ||
SET(TPL_ENABLE_MPI OFF CACHE BOOL "" FORCE) | ||
# Turn off Fortran support by default | ||
SET(${PROJECT_NAME}_ENABLE_Fortran_DEFAULT OFF) | ||
# Only one package in this simple project so just enable it :-) | ||
SET(${PROJECT_NAME}_ENABLE_HelloPackage ON CACHE BOOL "" FORCE) | ||
# Do all of the processing for this Tribits project | ||
TRIBITS_PROJECT() | ||
|
||
**SET(${PROJECT_NAME}_TRIBITS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tribits | ||
CACHE PATH "TriBITS base directory (default assumes in TriBITS source tree).")** | ||
Make sure you set this to your Tribits Installation path it may not be the same as | ||
this path. Now you should have a directory structure that looks like this:: | ||
|
||
. | ||
├── CMakeLists.txt | ||
├── PackagesList.cmake | ||
├── ProjectName.cmake | ||
├── TPLsList.cmake | ||
├── build | ||
└── hello_package_dir | ||
├── CMakeLists.txt | ||
├── cmake | ||
│ └── Dependencies.cmake | ||
└── src | ||
└── HelloWorld.cpp | ||
|
||
|
||
Build your TriBITS project | ||
--------------------------- | ||
Go to the build directory and type the following to configure your project:: | ||
cmake ../ | ||
|
||
You should see something very similar to:: | ||
|
||
..literalinclude:: HelloWorldConfigure.output | ||
|
||
The configure step will have created several files inside your build directory, most notably it will have created nessesary make files to | ||
actually build your project. The other file I will mention here is the CMakeCache.txt which stores information about how the project was | ||
configured. | ||
|
||
To build your project just type:: | ||
make | ||
|
||
you should see:: | ||
[ 50%] Building CXX object hello_package_dir/CMakeFiles/Hello-Executable-Name.dir/src/HelloWorld.cpp.o | ||
[100%] Linking CXX executable Hello-Executable-Name.exe | ||
[100%] Built target Hello-Executable-Name | ||
|
||
now in build/hello_package_dir you will see an executable named "Hello-Executable-Name" and if you run that executable you will see:: | ||
$ ./hello_package_dir/Hello-Executable-Name.exe | ||
Hello World! | ||
|
||
|
||
Adding other targets | ||
=============================== | ||
|
||
Types of targets | ||
----------------- | ||
Previously we had just one source file and we compiled it into one executable. In addition to executables we may also want to create other | ||
targets such as libraries abd tests. In the hello_package_dir/src directory create the following files: | ||
|
||
hello_world_main.cpp:: | ||
#include <iostream> | ||
#include "hello_world_lib.hpp" | ||
int main() { | ||
std::cout << HelloWorld::getHelloWorld() << "\n"; | ||
return 0; | ||
} | ||
|
||
hello_world_lib.hpp:: | ||
#include <string> | ||
namespace HelloWorld { std::string getHelloWorld(); } | ||
|
||
|
||
hello_world_lib.cpp:: | ||
#include "hello_world_lib.hpp" | ||
std::string HelloWorld::getHelloWorld() | ||
{ return "Hello World!"; } | ||
|
||
hello_world_unit_tests.cpp:: | ||
#include <iostream> | ||
#include "hello_world_lib.hpp" | ||
int main() { | ||
bool success = true; | ||
const std::string rtn = HelloWorld::getHelloWorld(); | ||
std::cout << "HelloWorld::getHelloWorld() = '"<<rtn<<"' == 'Hello World'? "; | ||
if (rtn == "Hello World!") { | ||
std::cout << "passed\n"; | ||
} | ||
else { | ||
std::cout << "FAILED\n"; | ||
success = false; | ||
} | ||
if (success) { | ||
std::cout << "All unit tests passed :-)\n"; | ||
} | ||
else { | ||
std::cout << "At least one unit test failed :-(\n"; | ||
} | ||
} | ||
|
||
We will use these files to build an executalbe, a library, and tests. Remember in the CMakeLists.txt file for the HelloPackage | ||
(hello_package_dir/CMakeList.txt) we have the line:: | ||
|
||
TRIBITS_ADD_EXECUTABLE(Hello-Executable-Name NOEXEPREFIX SOURCES src/HelloWorld.cpp INSTALLABLE) | ||
|
||
lets now modify that line to build an executable of the same name but using hello_world_main.cpp instead of HelloWorld.cpp:: | ||
|
||
TRIBITS_ADD_EXECUTABLE(Hello-Executable-Name NOEXEPREFIX SOURCES src/hello_world_main.cpp INSTALLABLE) | ||
|
||
to create a library we need to call TRIBITS_ADD_LIBRARY() and give it a name, headers and sources. add this the CMakeLists.txt:: | ||
|
||
TRIBITS_ADD_LIBRARY(hello_world_lib HEADERS src/hello_world_lib.hpp SOURCES src/hello_world_lib.cpp) | ||
|
||
we can also add tests. You can add a test based on an executable you have already specified for example:: | ||
|
||
TRIBITS_ADD_TEST(Hello-Executable-Name NOEXEPREFIX PASS_REGULAR_EXPRESSION "Hello World") | ||
|
||
will run "Hello-Executable-Name" and verify that the output is "Hello World". You can also add a test and an exectuable att he | ||
same time. for example:: | ||
|
||
TRIBITS_ADD_EXECUTABLE_AND_TEST(unit_tests SOURCES src/hello_world_unit_tests.cpp PASS_REGULAR_EXPRESSION "All unit tests passed") | ||
|
||
will create an executable named "unit_tests" from the source file hello_world_unit_tests.cpp. This executable will be used in a test | ||
that will be marked as passing if the output of that executable is "All unit tests passed". After making these changes and additions | ||
to the CMakeLists.txt file it should read:: | ||
|
||
TRIBITS_PACKAGE(HelloPackage) | ||
TRIBITS_ADD_LIBRARY(hello_world_lib HEADERS src/hello_world_lib.hpp SOURCES src/hello_world_lib.cpp) | ||
TRIBITS_ADD_EXECUTABLE(Hello-Executable-Name NOEXEPREFIX SOURCES hello_world_main.cpp INSTALLABLE) | ||
TRIBITS_ADD_TEST(Hello-Executable-Name NOEXEPREFIX PASS_REGULAR_EXPRESSION "Hello World") | ||
TRIBITS_ADD_EXECUTABLE_AND_TEST(unit_tests SOURCES hello_world_unit_tests.cpp PASS_REGULAR_EXPRESSION "All unit tests passed") | ||
TRIBITS_PACKAGE_POSTPROCESS() | ||
|
||
now reconfigure and rebuild in the build directory with:: | ||
cmake ../ | ||
make | ||
|
||
|
||
What did we build? | ||
======================================= | ||
|
||
In the build directory there are many new files created by TriBITS/CMake lets look at a few that are important for understanding how TriBITS | ||
is building your project. | ||
|
||
BUild Targets | ||
----------------- | ||
|
||
In the last section we built a library, an executable, and two tests. Where are they? look in:: | ||
|
||
build/hello_package_dir | ||
|
||
among other things you will see:: | ||
Hello-Executable-Name.exe | ||
HelloPackage_unit_tests.exe | ||
libhello_world_lib.a | ||
|
||
by default, TriBITS will place the targets inside a directory with the same name as the package directory. If you have more than one package | ||
then the files will be in separate directories:: | ||
|
||
build | ||
├── package_one | ||
│ ├── build_target_A | ||
│ └── build_target_B | ||
└── package_two | ||
├── build_target_C | ||
└── build_target_D | ||
|
||
You can install the built targets to the default location (/usr/local/bin) with:: | ||
make install | ||
|
||
You may want to install somewhere other than the default. In this case you want to set a CMamke variable called | ||
CMAKE_INSTALL_PREFIX. If this is set then the files will be installed to the directory specified. For example in the top level CMakeLists | ||
set this variable to a diecroyr called "Install" in the current source tree:: | ||
|
||
SET(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/Install) | ||
|
||
now clear the contents ofthe build directory and reconfigure, biuld, and install the project with:: | ||
cmake ../ | ||
make install | ||
|
||
Now you should see a directory calle "Install" in the top level of the project with contents:: | ||
|
||
tree | ||
. | ||
├── bin | ||
│ └── Hello-Executable-Name.exe | ||
├── include | ||
│ ├── Makefile.export.HelloPackage | ||
│ ├── Makefile.export.TribitsGreetings | ||
│ └── hello_world_lib.hpp | ||
└── lib | ||
├── cmake | ||
│ └── TribitsGreetings | ||
│ └── TribitsGreetingsConfigVersion.cmake | ||
└── libhello_world_lib.a |
Oops, something went wrong.