#!/usr/bin/env bash
#
# @license Apache-2.0
#
# Copyright (c) 2018 The Stdlib Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Script for compiling a C++ example.
#
# Usage: compile_cpp_example
#
# Arguments:
#
# filepath Example file path.
#
#
# Environment Variables:
#
# OS Host operating system. Default: `linux`.
# NODE Command for running Node.js. Default: `node`.
# NODE_PATH Path for resolving node modules.
# CXX_COMPILER C++ compiler. Default: `g++`.
# INCLUDE Includes (e.g., `-I /foo/bar -I /a/b`).
# SOURCE_FILES Source file list.
# LIBRARIES Linked libraries (e.g., `-lopenblas -lpthreads`).
# LIBPATH Library paths (e.g., `-L /foo/bar -L /a/b`).
#
# VARIABLES #
# Set the example file path:
file_path="$1"
# Define the host operating system:
os="${OS}"
if [[ "${os}" = "Darwin" ]]; then
os='mac'
elif [[ "${os}" = "WINNT" ]]; then
os='win'
else
os='linux'
fi
# Define the command for running Node.js:
node_cmd="${NODE}"
if [[ -z "${node_cmd}" ]]; then
node_cmd='node'
fi
# Define the node path:
node_path="${NODE_PATH}"
# Define the path to a C++ compiler:
cxx_compiler="${CXX_COMPILER}"
if [[ -z "${cxx_compiler}" ]]; then
cxx_compiler='g++'
fi
# Define a list of `include` directories (e.g., `-I /foo/bar -I /beep/boop/include`):
include="${INCLUDE}"
# Define a list of source files:
source_files="${SOURCE_FILES}"
# Define a list of libraries (e.g., `-lopenblas -lpthreads`):
libraries="${LIBRARIES}"
# Define a list of library paths (e.g., `-L /foo/bar -L /beep/boop`):
libpath="${LIBPATH}"
# FUNCTIONS #
# Defines an error handler.
#
# $1 - error status
on_error() {
echo 'ERROR: An error was encountered during execution.' >&2
cleanup
exit "$1"
}
# Runs clean-up tasks.
cleanup() {
echo '' >&2
}
# Prints a success message.
print_success() {
echo 'Success!' >&2
}
# Prints usage information.
usage() {
echo '' >&2
echo 'Usage: compile_cpp_example ' >&2
echo '' >&2
}
# Resolves a package path.
#
# $1 - source directory
resolve_pkg_path() {
local pkg_path
local script
# Generate the script for resolving a package path:
script='"'"var resolve = require('@stdlib/fs/resolve-parent-path').sync; var dirname = require('@stdlib/utils/dirname'); var opts = {'dir':'$1'}; var path = resolve('package.json', opts); console.log(dirname(path));"'"'
# Resolve package path:
pkg_path=$(eval NODE_PATH="${node_path}" "${node_cmd}" -e "${script}")
echo "${pkg_path}"
}
# Resolves a package `manifest.json`.
#
# $1 - package path
resolve_pkg_manifest() {
if [[ -e "$1/manifest.json" ]]; then
return 0
fi
return 1
}
# Resolves `include` directories.
#
# $1 - package directory
resolve_includes() {
local includes
local script
local opts
opts="{'task':'examples'}"
# Generate the script for resolving `include` directories:
script='"'"var path = require('path'); var arr = require('@stdlib/utils/library-manifest')(path.join('$1','manifest.json'),${opts},{'basedir':'$1','paths':'posix'}).include; var str = ''; for (var i = 0; i < arr.length; i++){var p = path.resolve('$1', arr[i]); str += '-I '+p+' ';}; console.log(str.substring(0, str.length-1));"'"'
# Resolve `include` directories:
includes=$(eval NODE_PATH="${node_path}" "${node_cmd}" -e "${script}")
echo "${includes}"
}
# Resolves source files.
#
# $1 - package directory
resolve_source_files() {
local source_files
local script
local opts
opts="{'task':'examples'}"
# Generate the script for resolving source files:
script='"'"var path = require('path'); var arr = require('@stdlib/utils/library-manifest')(path.join('$1','manifest.json'),${opts},{'basedir':'$1','paths':'posix'}).src; var str = ''; for (var i = 0; i < arr.length; i++){var p = path.resolve('$1', arr[i]); str += p+' ';}; console.log(str.substring(0, str.length-1));"'"'
# Resolve files:
source_files=$(eval NODE_PATH="${node_path}" "${node_cmd}" -e "${script}")
echo "${source_files}"
}
# Resolves libraries.
#
# $1 - package directory
resolve_libraries() {
local libraries
local script
local opts
opts="{'task':'examples'}"
# Generate the script for resolving libraries:
script='"'"var path = require('path'); var arr = require('@stdlib/utils/library-manifest')(path.join('$1','manifest.json'),${opts},{'basedir':'$1','paths':'posix'}).libraries; var str = ''; for (var i = 0; i < arr.length; i++){str += arr[i]+' ';}; console.log(str.substring(0, str.length-1));"'"'
# Resolve libraries:
libraries=$(eval NODE_PATH="${node_path}" "${node_cmd}" -e "${script}")
echo "${libraries}"
}
# Resolves library paths.
#
# $1 - package directory
resolve_libpaths() {
local libpath
local script
local opts
opts="{'task':'examples'}"
# Generate the script for resolving library paths:
script='"'"var path = require('path'); var arr = require('@stdlib/utils/library-manifest')(path.join('$1','manifest.json'),${opts},{'basedir':'$1','paths':'posix'}).libpath; var str = ''; for (var i = 0; i < arr.length; i++){var p = path.resolve('$1', arr[i]); str += '-L '+p+' ';}; console.log(str.substring(0, str.length-1));"'"'
# Resolve library paths:
libpath=$(eval NODE_PATH="${node_path}" "${node_cmd}" -e "${script}")
echo "${libpath}"
}
# Compiles example.
#
# $1 - source directory
compile() {
cd "$1" && CXX_COMPILER="${cxx_compiler}" INCLUDE="${include}" SOURCE_FILES="${source_files}" LIBRARIES="${libraries}" LIBPATH="${libpath}" make 2>&1
if [[ "$?" -ne 0 ]]; then
echo 'Error when attempting to compile example.' >&2
return 1
fi
echo 'Successfully compiled example.' >&2
return 0
}
# MAIN #
# Main execution sequence.
main() {
local pkg_path
local manifest
local src_dir
echo 'Resolving package path...' >&2
pkg_path=$(resolve_pkg_path "${src_dir}")
if [[ "$?" -ne 0 ]]; then
on_error 1
fi
echo "Package path: ${pkg_path}" >&2
echo 'Resolving package manifest...' >&2
manifest=$(resolve_pkg_manifest "${pkg_path}")
if [[ "$?" -eq 0 ]]; then
echo 'Successfully resolved package manifest.' >&2
if [[ -z "${include}" ]]; then
echo 'Resolving include directories...' >&2
include=$(resolve_includes "${pkg_path}")
if [[ "$?" -ne 0 ]]; then
on_error 1
fi
fi
if [[ -z "${source_files}" ]]; then
echo 'Resolving source files...' >&2
source_files=$(resolve_source_files "${pkg_path}")
if [[ "$?" -ne 0 ]]; then
on_error 1
fi
fi
if [[ -z "${libraries}" ]]; then
echo 'Resolving libraries...' >&2
libraries=$(resolve_libraries "${pkg_path}")
if [[ "$?" -ne 0 ]]; then
on_error 1
fi
fi
if [[ -z "${libpath}" ]]; then
echo 'Resolving library paths...' >&2
libpath=$(resolve_libpaths "${pkg_path}")
if [[ "$?" -ne 0 ]]; then
on_error 1
fi
fi
else
echo 'Unable to resolve package manifest.' >&2
fi
echo 'Compiling example...' >&2
src_dir=$(dirname "${file_path}")
compile "${src_dir}"
if [[ "$?" -ne 0 ]]; then
on_error 1
fi
print_success
cleanup
exit 0
}
# Handle arguments...
if [[ "$#" -eq 0 ]]; then
usage
exit 0
elif [[ "$#" -gt 1 ]]; then
echo 'ERROR: unrecognized arguments. Must provide a file path.' >&2
exit 1
fi
# Run main:
main