Skip to content

Commit

Permalink
squash - commit of WIP on tutorial documents
Browse files Browse the repository at this point in the history
  • Loading branch information
fryeguy52 committed Jun 14, 2017
1 parent 8c3b6c3 commit 8ced2e6
Show file tree
Hide file tree
Showing 2 changed files with 409 additions and 0 deletions.
361 changes: 361 additions & 0 deletions tribits/doc/tribits_tutorial/TribitsTutorialHelloWorld_0.rst
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
Loading

0 comments on commit 8ced2e6

Please sign in to comment.