Developing ISIS with cmake¶
Environmental Variables and Common Directories
Environmental Variables¶
$ISISROOT points to either:
-
(For Dev) The CMake build directory
ISISROOT=/yourCodeDirectory/ISIS3/build -
(For Production) The install directory for running a deployed copy of ISIS.
ISISROOT=$CONDA_PREFIX
$ISISDATA
Points to the NAIF SPICE Kernels, which contain spacecraft geometric and timing information that ISIS needs to process and align spacecraft images.
These kernels must be downloaded to process mission data, unless you are using the SpiceQL web service. See ISIS Data Area for more info on how to download and set up ISISDATA.
$ISISTESTDATA
Points to data for legacy ISIS Makefile tests. This data must be downloaded to run legacy tests. See ISIS Test Data.
Common Directories¶
Source Directory (ISIS3/isis):
Where the ISIS source code lives, the lowercase isis subdirectory of ISIS3. If you are in ISIS3/build, this would be ../isis as a relative path.
Build Directory (ISIS3/build):
Where generated project files live (Makefiles, Ninja files, Xcode project, etc).
Holds the bin directory where binaries are built to.
ninja (or make) commands should be run from here.
Executables Directory (ISIS3/build/bin):
Executables are placed in build/bin (and linked in $CONDA_PREFIX/bin).
For example, to run an ISIS app directly (with $ISISROOT set to the build directory):
Custom Data and Test Data:
The addition of test data files should be limited. Contributions to $ISISTESTDATA are no longer accepted.
If a test fixture requires extra data, that data should be placed in ISIS3/isis/tests/data.
Fork and Clone from GitHub¶
-
Make your own fork of ISIS:
Go to the main ISIS3 repo and click on "Fork" at the top of the page. -
Get a cloning link
On your ISIS fork (url should begithub.com/<username>/ISIS3), click on the greenClone or Downloadbutton on the right and copy the link. -
Clone ISIS (including submodules)
Open a terminal, go to the directory you want to make a clone in, and run:
git clone --recurse-submodules <your link> -
Checkout a branch
If you plan on contributing, create a branch with a short name to label your changes:
git checkout -b <branch-name>
Now that the files are on your computer, you can go on to build ISIS for yourself, and maybe even edit its programs or contribute to development.
Tracking Changes & Staying Updated - git branches & conda envs
Update git repo & dev branch
Before you make a new branch, you should make sure your git repository and dev branch are updated.
# Update your git repo
# (alternatively, open your repo online and click the sync button)
gh repo sync <your-username>/ISIS3
# Update your dev branch locally
git checkout dev
git pull
Checkout new branch
For each contribution, create a new branch to track its specific changes:
Update conda env
After making a new branch, make a new conda environment to ensure dependencies are updated. You may remove environments for branches you are done working on.
Cloning Submodules later
(if you didn't run --recurse-submodules, or are missing gtest)
If you have an old clone, or you forgot to add --recurse-submodules when you initially cloned ISIS, run this in the ISIS3 directory to clone the gtest submodule:
Build Environment & Dependencies¶
Conda manages dependencies and 3rd-party libraries to create a build environment (conda env) for ISIS. The cmake build system expects an active conda env containing these dependencies, which are listed in the environment.yml.
Getting Conda¶
Building ISIS requires conda. If you need conda, install it through miniforge:
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
bash Miniforge3-$(uname)-$(uname -m).sh
Cleaning Conda Envs¶
Don't reuse a conda env used to build an older version of ISIS. This can cause errors if the dependencies were updated. If you need to start with a clean slate:
# Remove an Old/Unneeded Environment
conda env remove -n isis-dev-env -y
# Remove cached packages
conda clean --all
Creating/Activating an Env¶
To create and activate a conda env, run these commands in the ISIS3 directory.
We chose the env name, "isis-dev-env", but you can name your env something else if you want.
Your terminal prompt should look now be preceded by (isis-dev-env).
This indicates that you are in an active conda env,
which you will need to build ISIS.
Building ISIS¶
1. Create a build directory¶
There should now be a "build" subdirectory alongside the "isis" subdirectory.
ninja (or make) commands should be run from inside the build directory.
2. Set Env Variables¶
Set ISISROOT to point to your build directory.
See the ISIS Data Area
to set up ISISDATA and ISISTESTDATA so you can import mission data and run tests.
export ISISROOT=/yourCodeDirectory/ISIS3/build
export ISISDATA=/yourDataDirectory/isisdata
export ISISTESTDATA=/yourDataDirectory/isistestdata
# You may want to add these to your .bashrc or .zshrc,
# so you don't have to set them every time.
3. Make ISIS with cmake¶
If you run cmake from a different directory, change ../isis to point to the isis subfolder under ISIS3.
Rerun the cmake command whenever you add/remove objects, so the system can see/compile them.
4. Build ISIS with ninja¶
Ninja vs Make
We generally use ninja to build ISIS, though it is possible to configure cmake for
plain make builds as well, omitting the -GNinja flag:
ninja tends to be faster - it relinks dependencies instead of rebuilding them all.
make compiles and builds everything your class touches again (slow),
but ninja just recompiles your class and relinks dependencies (faster).
In the case of a heavily used class like Pixel, this equates to 865 objects. It's still much faster then using cmake generated Makefiles.
Build Tasks and Custom Builds¶
Cmake Build Configuration Flags
Use these flags in the cmake command to configure your build.
Flags with an = sign are shown with their default values.
Some can be turned ON or OFF, others accept a specific value.
General cmake Flags
-GNinja
Makes a Ninja Makefile (alternative to GNU make). To use plain make instead, omit this flag and replace the ninja commands with their make counterparts.
-DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX$
Sets the path that ISIS will be installed to when ninja install is run.
-DCMAKE_BUILD_TYPE=Release
Build type. Release by default, can also be set to Debug.
ISIS-Specific Flags
-DisisData=OFF
The ISISDATA directory. If OFF, the $ISISDATA environmental variable will be used by default.
-DisisTestData=OFF
The ISISTESTDATA directory. If OFF, the $ISISTESTDATA environmental variable will be used by default.
-DtestOutputDir=OFF
Directory to store app test output folders. If OFF, then ${CMAKE_BINARY_DIR}/testOutputDir will be used by default.
-DbuildCore=ON
Build core ISIS modules.
-DbuildMissions=ON
Build mission-specific modules.
-DbuildStaticCore=OFF
Build libisis static libraries (in addition to dynamic, which are always built).
-DbuildTests=ON
Tests.
-DbuildCoverage=ON
Code coverage.
-DbuildDocs=ON
Documentation
-DJP2KFLAG=OFF
JPEG2000 support. (Not available on ARM builds.)
-Dpybindings=ON
Bundle adjust python bindings.
Build Options Source:
Most of the above options are spelled out in ISIS's CMakeLists.txt file.
Look for # Configuration options in isis/CMakeLists.txt.
Use -D... flags to turn these options on or off.
For example, to build ISIS with no tests and no docs:
Installing to a Custom Directory
# Create a directory for your install
mkdir install
# Go to your build dir. Set the install dir in the cmake command.
cd build
cmake -DCMAKE_INSTALL_DIRECTORY=/path/to/your/install -GNinja ../isis
# install with ninja
ninja install
# Add install dir to your path so you can run the apps from any directory
# Place this command in your .bashrc or .zshrc to make permanent
export PATH="$PATH:/path/to/your/install"
Cleaning Builds
Removes all built objects except for those built by the build generator:
ninja -t clean
Remove all built objects for a specific target:
ninja -t clean <target_name>
Get a list of Ninja's targets:
ninja -t targets
Cleaning all of ISIS:
rm -rf build
Cleaning an individual app:
cd build && rm bin/<app_name>
Cleaning an individual object:
cd build && rm `find -name ObjectName.cpp.o`
Building Individual ISIS Applications
Building Individual ISIS Objects
Building Only Documentation
The documentation is placed in build/docs.
Cmake is configured to build docs by defaults, but if the -DbuildDocs=OFF flag was used,
ninja and make won't be able to build the docs until you run cmake again.
Building in Debug Mode
Tests¶
ISIS Test Data¶
See ISIS Test Data for info on downloading and setting up the data used in legacy makefile-based tests.
Identifying Tests¶
The test names are as follows:
- unit test :
<modulename>_unit_test_<objectname> - app test :
<appname>_app_test_<testname> - cat test :
<modulename>_module_test_<testname>
All cat tests under base, database, control, qisis, and system are listed under the isis3 module.
Running Tests¶
ISIS tests now work through ctest. Unit tests are by default put into the build/unitTest directory. The most simple way to run test of a certain type is using the -R <regex> option, which only runs tests which match the regex.
It is important to note the many of the tests rely on an ISISROOT environment variable to be set to the build directory. If it is not set you will see almost all tests fail.
App test must have the bin in the build directory appended to the environment path.
Using the setisis script on your build directory should fix these environment issues for you.
# inside your build directory
ctest # run all tests
ctest -R _unit_ # run unit tests
ctest -R _app_ # run app tests
ctest -R _module_ # run module (cat) tests
ctest -R jigsaw # run jigsaw's app tests
ctest -R lro # run all lro tests
ctest -E tgo # Run everything but tgo tests
Building New Tests¶
The workflow for creating a new tests will be the same as the old ISIS make system besides adding test data. See Make Truth Replacement below for how this set in the process changes.
App Tests and Category Tests¶
App/Category tests still use the old make system, with the standard ISIS app/category test workflow.
App/Category tests can be developed in the ISIS src tree similar to the old make system. As long as the path is pointing to the binaries in the build directory (build/bin); make output, make test, make compare, make truthdata, and make ostruthdata all work. You cannot run all tests from the root of the ISIS source tree. To accomplish this use ctest in the build directory, see above. If there is testdata in the ISIS source tree ctest will test with that data.
Unit Tests¶
Unit tests don't use the old ISIS make system. The unitTest.cpp of each object are compiled and an executable is made and saved in the unitTest sub-directory of the build directory. A symbolic link of the unit test executable is created in the object's directory. This allows the unit test to get files that it needs inside the object's directory, i.e. unitTest.xml. If a unit test passes, then the symbolic link is removed. If you want to run a passing unit test in debug mode, you will have to create a symbolic link of the unit test in the object's directory yourself. If you are inside the object's directory:
ln -s $ISISROOT/unitTest/<unit_test_name> unitTest
Steps To Create A New UnitTest:
- Create unitTest.cpp under new object directory in ISIS src tree
- re-configure cmake
- rebuild
- Use makeOutput.py (see below) to create new truth data
Example Ctest Output
98% tests passed, 7 tests failed out of 394
Total Test time (real) = 171.11 sec
The following tests FAILED:
11 - isis3_unit_test_Application (Failed)
97 - isis3_unit_test_IException (Failed)
174 - isis3_unit_test_Pipeline (Failed)
201 - isis3_unit_test_ProcessExportPds4 (Failed)
211 - isis3_unit_test_ProgramLauncher (Failed)
303 - isis3_unit_test_UserInterface (Failed)
338 - isis3_unit_test_MosaicSceneWidget (Failed)
Errors while running CTest
- To learn more about Ctest, check out the Ctest Docs
Make Truth Replacement¶
The MakeTruth functionality that exists in the Makefiles of the old make system now exists in a script (makeOutput.py) located in ISIS3/isis/scripts/makeOutput.py.
A developer will want output of a test before setting it as truth data. This is currently done with the following command in the form of:
python3 makeOutput.py test
where test is the cmake name for the unit or app test. It is important to note that this command must be ran from the the src directory, i.e., the object's directory that output is being made for.
For unit tests, this will output a file in the form of build/testOutputDir.
For app tests, this will output a directory (truth) in the directory build/testOutputDir that contains the truth data for the app test.
To check in truth data the command should be in the form of:
python3 makeOutput.py -t test
Example makeOutput.py for object Apollo:
command: python3 $ISISROOT/../isis/scripts/makeOutput.py apollo_unit_test_Apollo
output: Unit Test Output In /scratch/cmake/isis3_cmake/build/testOutputDir/ As Apollo.truth
command: python3 $ISISROOT/../isis/scripts/makeOutput.py apollo_unit_test_Apollo -t
output: Checked In Truth Data To /scratch/cmake/isis3_cmake/isis/src/apollo/objs/Apollo/Apollo.truth
-
For unit tests, you will need to rename the output put in build/testOutputDir as
<objectname>_<OStype>_x86_64_<OSname>.truth. If we wanted to make Mac truth data for ProgramLauncher: "ProgramLauncher_Darwin_x86_64_MacOSX10_13.truth". -
For app tests, you will need to rename the truth directory put in build/testOutputDir as
truth.<OStype>.x86_64.<OSname>. If we wanted to make Mac truth data: "truth.Darwin.x86_64.MacOSX10_13".
Checking Test Coverage¶
ISIS uses gcovr to track test coverage. PRs will not be approved if they drop coverage by more than 2%, though exceptions can be made for large feature adds. This step happens after tests have run, as coverage is detected based on the last ctest run.
ninja test_coverage_ascii # generate ascii table to stdout
ninja test_coverage_html # generate interactive webpage
# open HTML at $ISIS_BUILD_DIR/test_coverage_html/index.html
The remote CI coverage checks (on the PR) generate an ASCII table. Locally, generating HTML reports is recommended, as they contain interactive access to line hits and misses.
When reading CI coverage on ISIS CI builds, test coverage will be at the bottom of the logs once CI is complete. The CI first builds, then tests, then checks test coverage. You may have to scroll quite a bit to reach the desired section.
Test Results and Coverage Report in ISIS CI Build Log
100% tests passed, 0 tests failed out of 2705
Total Test time (real) = 2145.30 sec
The following tests did not run:
1258 - TempTestingFiles.FunctionalTestJitterfitDefault (Disabled)
1302 - TempTestingFiles.UnitTestImageImporterTestJpeg (Disabled)
1553 - DefaultCube.FunctionalTestNoprojExpand (Disabled)
1900 - MroCtxCube.FunctionalTestCtxcalDefault (Disabled)
1903 - MroCtxCube.FunctionalTestCtxcalIofFalse (Disabled)
[1/1] Generating gcovr ASCII coverage report.
(INFO) Reading coverage data...
(INFO) Writing coverage report...
------------------------------------------------------------------------------
GCC Code Coverage Report
Directory: .
------------------------------------------------------------------------------
File Lines Exec Cover Missing
------------------------------------------------------------------------------
src/apollo/apps/apollo2isis/main.cpp 242 0 0% 50-54,56,58-59,61,63,66-68,71-72,74,77-78,80,82-84,87,89-100,102-105,112-116,119-124,126,131-145,147-150,152-155,158-160,163-164,167-176,178-179,181-182,185-188,193-195,198,200-205,207-209,213-216,219,223,228,230-232,234-236,238-244,246-250,252-253,255-257,260-263,265-266,269,272-273,275,278-283,286-288,290-292,295-298,300,302-307,310-315,318-328,331-333,336-338,341-343,347-350,355-357,359-361,363-365,369-371,374-384,386-387,389-393,395,398-401,403,406-408
src/apollo/apps/apollocal/apollocal.cpp 38 33 86% 26-29,74
src/apollo/apps/apollocal/main.cpp 4 0 0% 16-19
.
. Snip, many such files
.
src/voyager/apps/voycal/main.cpp 173 140 80% 69-72,82-85,90-93,118-123,155-160,247,312-314,334,343,345,347,349
src/voyager/apps/voyramp/main.cpp 85 71 83% 75-78,82-84,95-99,197-198
src/voyager/objs/VoyagerCamera/VoyagerCamera.cpp
78 67 85% 87-90,111-114,133-135
------------------------------------------------------------------------------
TOTAL 130854 102073 78%
------------------------------------------------------------------------------
lines: 78.0% (102073 out of 130854)
functions: 86.4% (7023 out of 8131)
branches: 42.6% (121959 out of 286413)
You should check your results to the last dev build to see if your coverage increased or decreased.
Static Code Checking¶
ISIS uses cppcheck for static code checking, to catch security vulnerabilities and undefined behavior that other methods may miss. In ISIS CI, this is checked after running tests, close to the end of the log.
cppcheck your-new-contribution.cpp --enable=all --suppress=missingInclude --suppress=missingIncludeSystem --suppress=unmatchedSuppression
Troubleshooting¶
If you get the following error message when trying to set up your environment:
conda env create -n cmake -f environment.yml
Using Anaconda Cloud api site https://api.anaconda.org
Error: invalid package specification: ninja==1.7.2=0
Update your conda installation using conda update and then try again.
If you get the following error message while testing on a Mac:
bash: line 10: /usr/local/bin/grep: No such file or directory
bash: line 11: /usr/local/bin/grep: No such file or directory
bash: /usr/local/bin/grep: No such file or directory
Check to see if grep is installed in /usr/local/bin. If grep is not installed, install grep with Homebrew:
brew install grep -with-default-names
This will install GNU grep under the name "grep". If you do not add the flag at the end, GNU grep will be installed under "ggrep" instead.
If ggrep is installed, run the following commands: