{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"\n",
"# BlackHoles@Home Tutorial: Compiling the `BOINC` libraries\n",
"\n",
"## Author: Leo Werneck\n",
"\n",
"## This tutorial notebook demonstrates how to compile the `BOINC` libraries on different platforms\n",
"\n",
"## Introduction:\n",
"\n",
"The [BlackHoles@Home](http://blackholesathome.net/) project allows users to volunteer CPU time so a large number of binary black holes simulations can be performed. The objective is to create a large catalog of [gravitational waveforms](https://en.wikipedia.org/wiki/Gravitational_wave), which can be used by observatories such as [LIGO](https://www.ligo.org), [VIRGO](https://www.virgo-gw.eu), and, in the future, [LISA](https://lisa.nasa.gov) in order to infer what was the source of a detected gravitational wave.\n",
"\n",
"BlackHoles@Home is destined to run on the [BOINC](https://boinc.berkeley.edu) infrastructure (alongside [Einstein@Home](https://einsteinathome.org/) and [many other great projects](https://boinc.berkeley.edu/projects.php)), enabling anyone with a computer to contribute to the construction of the largest numerical relativity gravitational wave catalogs ever produced.\n",
"\n",
"### Additional Reading Material:\n",
"\n",
"* [BOINC's Wiki page](https://boinc.berkeley.edu/trac/wiki)\n",
"* [Debian's Wiki BOINC server guide](https://wiki.debian.org/BOINC/ServerGuide/Initialisation)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Table of Contents\n",
"$$\\label{toc}$$\n",
"\n",
"This tutorial compiles the `BOINC` libraries. It will also install all needed dependencies. We test everything is okay by compiling and running a simple \"Hello World!\" application that makes use of the `BOINC` libraries. This tutorial is organized as follows:\n",
"\n",
"1. [Step 1](#loading_python_nrpy_modules): Loading necessary Python/NRPy+ modules\n",
"1. [Step 2](#compilation_script): A simple script to compile the `BOINC` libraries\n",
"1. [Step 3](#compilating_boinc_libraries): Compiling the `BOINC` libraries\n",
"1. [Step 4](#compilation_test): Compiling a simple program\n",
"1. [Step 5](#latex_pdf_output): Output this notebook to $\\LaTeX$-formatted PDF file"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Step 1: Loading needed Python/NRPy+ modules \\[Back to [top](#toc)\\]\n",
"$$\\label{loading_python_nrpy_modules}$$\n",
"\n",
"We start by loading the necessary Python/NRPy+ moduels used by this tutorial notebook. We also set up the `BOINC` directory path (the default path is the current working directory)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Step 1: Import necessary modules - set directories.\n",
"# Step 1.a: Import required Python modules\n",
"import os,sys,shutil\n",
"\n",
"# Step 1.b: Add NRPy's root directory to the sys.path()\n",
"sys.path.append(\"..\")\n",
"\n",
"# Step 1.c: Load NRPy+'s command line helper module\n",
"import cmdline_helper as cmd\n",
"\n",
"# Step 1.d: Set directories needed by this tutorial notebook\n",
"boinc_base_dir = \"/Users/werneck/bhah\" # os.getcwd()\n",
"boinc_root_dir = os.path.join(boinc_base_dir,\"boinc\")\n",
"boinc_lib_dir = os.path.join(boinc_root_dir,\"lib\")\n",
"boinc_api_dir = os.path.join(boinc_root_dir,\"api\")\n",
"boinc_zip_dir = os.path.join(boinc_root_dir,\"zip\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Step 2: A simple script to compile the `BOINC` libraries \\[Back to [top](#toc)\\]\n",
"$$\\label{compilation_script}$$\n",
"\n",
"We will now write a simple `bash` script that will take care of downloading the `BOINC` source code and compiling the `BOINC` libraries.\n",
"\n",
"The script performs the following tasks:\n",
"\n",
"1. Install the necessary dependencies.\n",
"1. Download the [`BOINC` source code](https://github.com/BOINC/boinc) (if necessary).\n",
"1. Compile the `BOINC` core, api, and zip libraries.\n",
"\n",
"The `BOINC` library require the following packages:\n",
"\n",
"1. git\n",
"1. make\n",
"1. m4\n",
"1. autoconf\n",
"1. libtool\n",
"1. A C++ compiler\n",
"\n",
"In Linux, we will be using the [GNU compilers](https://gcc.gnu.org) installed using [`aptitude`](http://manpages.ubuntu.com/manpages/bionic/man8/aptitude-curses.8.html) in Ubuntu and Debian. In Mac OS X, we will be using the [LLVM compilers](https://llvm.org) installed using [`homebrew`](https://brew.sh)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Step 2: Write down a script to compile the BOINC libraries\n",
"# Step 2.a: Check the platform. This will adjust the way we install the dependencies.\n",
"platform = sys.platform\n",
"compiler_config = \"\"\n",
"if platform == \"linux\":\n",
" # In Ubuntu/Debian, use aptitude to install the dependencies.\n",
" # To avoid issues where the user does not have sudo priviledges,\n",
" # such as in mybinder, we check if we find the command first.\n",
" dependency_list = [\"git\",\"make\",\"m4\",\"autoconf\",\"libtool\",\"g++\"]\n",
" dependencies = \"\"\n",
" for dependency in dependency_list:\n",
" path = shutil.which(dependency)\n",
" if path is not None:\n",
" dependencies += dependency+\" \"\n",
" else:\n",
" print(dependency+\" found at \"+path)\n",
" \n",
" if dependencies != \"\":\n",
" install_dependencies = \"sudo apt install -y \"+dependencies\n",
"elif platform == \"darwin\":\n",
" # In Mac OS X, use homebrew to install the dependencies.\n",
" install_dependencies = \"brew install git make m4 autoconf libtool llvm\"\n",
" # Because we use clang/clang++ instead of gcc/g++, we need\n",
" # to specify additional compilation flags to help the build\n",
" # script locate all the header files and libraries we will\n",
" # need. The paths below assume that the llvm compilers are\n",
" # in the default brew path /usr/local/opt. Adjust the\n",
" # variable 'path_to_llvm' if that's not the case.\n",
" path_to_llvm = \"/usr/local/opt/llvm/\"\n",
" path_to_clang = os.path.join(path_to_llvm,\"bin\",\"clang\")\n",
" path_to_clangpp = os.path.join(path_to_llvm,\"bin\",\"clang++\")\n",
" path_to_clang_include = os.path.join(path_to_llvm,\"include\")\n",
" path_to_clang_library = os.path.join(path_to_llvm,\"lib\")\n",
" CPPFLAGS = \"-I%s\"%(path_to_clang_include)\n",
" LDFLAGS = \"-L%s\"%(path_to_clang_library)\n",
" compiler_config = \"CC=%s CXX=%s OBJC=%s CPPFLAGS=\\\"%s\\\" LDFLAGS=\\\"%s\\\" \"%(path_to_clang,\n",
" path_to_clangpp,\n",
" path_to_clang,\n",
" path_to_clang_include,\n",
" path_to_clang_library)\n",
"else:\n",
" print(\"Error: platform %s is currently not supported.\"%platform)\n",
" sys.exit(1)\n",
" \n",
"with open(\"compile_BOINC_libraries.sh\",\"w\") as file:\n",
" file.write(r\"\"\"#!/bin/bash\n",
"\n",
"# Install all required software\n",
"%s\n",
"\n",
"# Download BOINC repository (if necessary)\n",
"boincdir=%s\n",
"if [ -d \"$boincdir\" ]; then\n",
" echo \"BOINC directory found at $boincdir\"\n",
"else\n",
" echo \"BOINC directory not found at $boincdir. Cloning from BOINC github repository...\"\n",
" git clone https://github.com/BOINC/boinc boinc\n",
"fi\n",
"\n",
"# Now change directories to the BOINC directory\n",
"cd \"$boincdir\"\n",
"\n",
"# Compile the core BOINC libraries\n",
"./_autosetup -f\n",
"%s./configure --disable-client --disable-manager --disable-server\n",
"make\n",
"\n",
"# Now compile the boinc_zip library\n",
"cd %s\n",
"make\n",
"\"\"\"%(install_dependencies,boinc_root_dir,compiler_config,boinc_zip_dir))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Step 3: Compiling the `BOINC` libraries \\[Back to [top](#toc)\\]\n",
"$$\\label{compilating_boinc_libraries}$$\n",
"\n",
"We now run the script above to compile the `BOINC` libraries. This tutorial notebook has been tested in the following systems:\n",
"\n",
"1. Ubuntu 20.04 LTS.\n",
"1. Mac OS X Big Sur (version 11.2.3).\n",
"\n",
"If all the dependencies are already installed, then the script should finish running in just a few minutes. If not, then it will download the dependencies and the execution time may vary depending on your internet connection speed."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Now compiling BOINC libraries (can take a few minutes depending on your internet connection) ...\n",
"Finished compiling BOINC libraries\n"
]
}
],
"source": [
"# Step 3: Compile the BOINC libraries\n",
"# FIXME: I don't think this is the best way of doing this.\n",
"print(\"Now compiling BOINC libraries (can take a few minutes depending on your internet connection) ...\")\n",
"status = os.system(\"source compile_BOINC_libraries.sh\")\n",
"print(\"Finished compiling BOINC libraries\" if status == 0 \n",
" else \"Error: Something went wrong when compiling the BOINC libraries.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Step 4: Compiling a simple program \\[Back to [top](#toc)\\]\n",
"$$\\label{compilation_test}$$\n",
"\n",
"We now compile a \"Hello World!\" program that makes use of the `BOINC` libraries. This will help us know if everything is okay with the compilation of the libraries."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Running hello_boinc program...\n",
"Hello BOINC!\n",
"All done!\n"
]
}
],
"source": [
"# Step 3: Compiling a test program\n",
"# Step 3.a: Write down a \"Hello World!\" program that uses the BOINC libraries\n",
"outfile = \"hello_boinc.cpp\"\n",
"with open(outfile,\"w\") as file:\n",
" file.write(r\"\"\"\n",
"// Core C++ input/output header\n",
"#include \n",
"\n",
"// BOINC API header\n",
"#include \"boinc_api.h\"\n",
"\n",
"// Main program\n",
"int main(int argc, char** argv) {\n",
"\n",
" // Initialize the boinc environment\n",
" int status = boinc_init();\n",
" \n",
" // Check everything is okay\n",
" if( status != 0 ) {\n",
" fprintf(stderr,\"Error: boinc_init() returned a non-zero value: %d. Terminating.\",status);\n",
" boinc_finish(status);\n",
" }\n",
" \n",
" // Print a message to the user\n",
" printf(\"Hello BOINC!\\n\");\n",
" \n",
" // Terminate the program with no errors\n",
" boinc_finish(0);\n",
" \n",
" // All done!\n",
"}\n",
"\"\"\")\n",
"\n",
"# Step 3.b: Add the base nrpytutorial directory to sys.path()\n",
"import sys\n",
"sys.path.append('..')\n",
"\n",
"# Step 3.c: Import the cmdline_helper NRPy+ module\n",
"import cmdline_helper as cmd\n",
"\n",
"# Step 3.d: Prepare to compile\n",
"# Step 3.d.i: Set the C++ compiler flags\n",
"CXXFLAGS = \"-I%s -I%s \"%(boinc_api_dir,boinc_lib_dir)\n",
"LDFLAGS = \"-L%s -L%s -lboinc_api -lboinc \"%(boinc_api_dir,boinc_lib_dir)\n",
"\n",
"# Step 3.d.ii: Set the C++ compiler\n",
"if platform == 'linux':\n",
" CXX_compiler = \"g++ \"\n",
"elif platform == 'darwin':\n",
" CXX_compiler = \"clang++ \"\n",
" CXXFLAGS += \"-I%s \"%(path_to_clang_include)\n",
" LDFLAGS += \"-L%s \"%(path_to_clang_library)\n",
"else:\n",
" print(\"Error: platform %s is currently not supported.\"%platform)\n",
" sys.exit(1)\n",
"\n",
"# Step 3.d.iii: Compile the program\n",
"CXX_compile_string = CXX_compiler+CXXFLAGS+\"hello_boinc.cpp -o hello_boinc \"+LDFLAGS\n",
"os.system(CXX_compile_string)\n",
"\n",
"# Step 3.d.iv: Run the program\n",
"print(\"Running hello_boinc program...\")\n",
"!./hello_boinc\n",
"print(\"All done!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Step 5: Output this notebook to $\\LaTeX$-formatted PDF file \\[Back to [top](#toc)\\]\n",
"$$\\label{latex_pdf_output}$$\n",
"\n",
"The following code cell converts this Jupyter notebook into a proper, clickable $\\LaTeX$-formatted PDF file. After the cell is successfully run, the generated PDF may be found in the root NRPy+ tutorial directory, with filename\n",
"[Tutorial-BlackHolesAtHome-Compiling_the_BOINC_libraries.pdf](Tutorial-BlackHolesAtHome-Compiling_the_BOINC_libraries.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means.)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"execution": {
"iopub.execute_input": "2021-03-07T17:21:21.309338Z",
"iopub.status.busy": "2021-03-07T17:21:21.308582Z",
"iopub.status.idle": "2021-03-07T17:21:24.791779Z",
"shell.execute_reply": "2021-03-07T17:21:24.792580Z"
},
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Created Tutorial-BlackHolesAtHome-Compiling_the_BOINC_libraries.tex, and\n",
" compiled LaTeX file to PDF file Tutorial-BlackHolesAtHome-\n",
" Compiling_the_BOINC_libraries.pdf\n"
]
}
],
"source": [
"!cp ../latex_nrpy_style.tplx .\n",
"cmd.output_Jupyter_notebook_to_LaTeXed_PDF(\"Tutorial-BlackHolesAtHome-Compiling_the_BOINC_libraries\")\n",
"!rm -f latex_nrpy_style.tplx"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}