From 8f3c2c78c91e389b84aad9a9ece7dd04bd54b552 Mon Sep 17 00:00:00 2001 From: Russ Tedrake Date: Sun, 2 Aug 2015 17:50:56 -0400 Subject: [PATCH] first pass at make logic ported from drake-distro --- CMakeLists.txt | 254 +++++++++++++++++++++++++++++++++++++++++++++ Makefile | 94 +++++++++++++++++ addpath_pods.m | 13 +++ install_prereqs.sh | 30 ++++++ 4 files changed, 391 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 addpath_pods.m create mode 100755 install_prereqs.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000000..d2e3f033d846 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,254 @@ +cmake_minimum_required(VERSION 2.8.0) +project(drake-superbuild) + +include(ExternalProject) + +option(AUTO_UPDATE_EXTERNALS "external projects are updated to their tag revision on compile" ON) + +# chinese menu of external projects +option(WITH_ALL_SUPPORTED_EXTERNALS "overrides the individual WITH_[external] options" OFF) +option(REMOVE_UNUSED_EXTERNALS "enable this to remove those projects from disk" OFF) + +# ON by default: +option(WITH_EIGEN "required c++ matrix library. only disable if you have it already." ON) +option(WITH_LCM "interprocess communications protocol for visualizers, etc" ON) +option(WITH_BULLET "used for collision detection" ON) +option(WITH_SPOTLESS "polynomial optimization front-end for MATLAB" ON) + +# OFF by default: +option(WITH_DIRECTOR "vtk-based visualization tool and robot user interface") +option(WITH_IRIS "fast approximate convex segmentation") +option(WITH_OCTOMAP "provides oct-tree data structures") +option(WITH_SNOPT "nonlinear optimization solver; requires access to RobotLocomotion/snopt-pod") +option(WITH_GUROBI "convex/integer optimization solver; free for academics (will prompt you for login bits)") +option(WITH_MOSEK "convex optimization solver; free for academics") +option(WITH_YALMIP "free optimization front-end for MATLAB") +option(WITH_GLOPTIPOLY "free global polynomial optimization tooblox") +option(WITH_BERTINI "solve polynomial equations; free but pod requires permissions (can't redistribute)") +option(WITH_SEDUMI "semi-definite programming solver") +option(WITH_AVL "use w/ XFOIL to compute aerodynamic coefficients for airfoils") +option(WITH_XFOIL "use w/ AVL to compute aerodynamic coefficients for airfoils") + +# system dependent defaults: +if (WIN32) + option(WITH_GTK "precompiled gtk binaries/headers for Windows" ON) + option(WITH_LIBBOT "simple open-gl visualizer + lcmgl for director" OFF) +else() + option(WITH_GTK "precompiled gtk binaries/headers for Windows" OFF) + option(WITH_LIBBOT "simple open-gl visualizer + lcmgl for director" ON) +endif() + + +set(MAKE_EXECUTABLE $ENV{MAKE}) +if (NOT MAKE_EXECUTABLE) + find_program(MAKE_EXECUTABLE make) + if (NOT MAKE_EXECUTABLE) + message(FATAL_ERROR "couldn't find gnu make") + endif() +endif() +set(MAKE_COMMAND ${MAKE_EXECUTABLE} $ENV{MAKEFLAGS}) # didn't work on my first test, but should do no harm + +# process optional projects +# note: keep drake in this loop in case externals depend on drake (e.g. the director might in the near future) +set(EXTERNAL_PROJECTS) +foreach(proj IN ITEMS eigen gtk lcm libbot bullet iris spotless director octomap snopt gurobi mosek yalmip gloptipoly bertini sedumi avl xfoil drake) + string(TOUPPER ${proj} proj_upper) + if (${proj} STREQUAL "drake" OR WITH_${proj_upper} OR WITH_ALL_SUPPORTED_EXTERNALS) + list(APPEND EXTERNAL_PROJECTS ${proj}) + elseif(REMOVE_UNUSED_EXTERNALS AND IS_DIRECTORY ${proj}) + message(STATUS "removing unused project: ${proj}") + execute_process(COMMAND ${MAKE_COMMAND} BUILD_PREFIX=${CMAKE_INSTALL_PREFIX} BUILD_TYPE=${CMAKE_BUILD_TYPE} clean + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${proj}) + execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${PROJECT_SOURCE_DIR}/${proj}") + endif() +endforeach() + +# throw error for unsupported platform/project combinations +macro( unsupported ) + foreach(proj ${ARGN}) + list(FIND EXTERNAL_PROJECTS ${proj} find_result) + if (NOT find_result EQUAL -1) + if (WITH_ALL_SUPPORTED_EXTERNALS) + list(REMOVE_ITEM EXTERNAL_PROJECTS ${proj}) + else() + message(FATAL_ERROR ${proj} is not supported (yet) on this platform) + endif() + endif() + endforeach() +endmacro() + +if (WIN32) + unsupported(libbot octomap gurobi mosek yalmip gloptipoly bertini sedumi avl xfoil iris director) # many of these could potentially work, but haven't been tried +endif() + +#enable_language(Fortran) +#if (NOT CMAKE_Fortran_COMPILER) +# unsupported(avl xfoil) +#endif() + +# list *compilation* dependencies, in alphabetical order by target (note: dependencies must come first in my foreach above) +set(lcm_dependencies gtk) +set(libbot_dependencies lcm) +set(director_dependencies lcm libbot) +set(drake_dependencies eigen lcm libbot bullet octomap snopt gurobi) + +# download information, in alphabetical order +find_package(Git QUIET) +set(avl_GIT_REPOSITORY https://github.com/RobotLocomotion/avl.git) +set(avl_GIT_TAG 9b927f90619460b29f7454c714369f65bc4536a1) +set(bertini_GIT_REPOSITORY https://github.com/RobotLocomotion/bertini.git) +set(bertini_GIT_TAG 3ae3e3ad3534acb4b6f7a4c3c22728b493beaa80) +set(bullet_GIT_REPOSITORY https://github.com/RobotLocomotion/bullet-pod.git) +set(bullet_GIT_TAG 6db7ae5e29f8b35ffcea384c53caa4bddcc6f986) +set(director_GIT_REPOSITORY https://github.com/RobotLocomotion/director.git) +set(director_GIT_TAG f44045f75e931165d9f519b989bdbd1ad8e70b08) +set(director_SOURCE_DIR ${PROJECT_SOURCE_DIR}/externals/director/distro/pods/drake-distro) +set(eigen_GIT_REPOSITORY https://github.com/RobotLocomotion/eigen-pod.git) +set(eigen_GIT_TAG fb56a4b8504eb115a7f257de4570c47c20c43397) +if (NOT drake_GIT_REPOSITORY) + set(drake_GIT_REPOSITORY https://github.com/RobotLocomotion/drake.git) +endif() +if (NOT drake_GIT_TAG) + set(drake_GIT_TAG d3ff393f9639135c6d421a311e789773fdc74701) +endif() +set(gtk_GIT_REPOSITORY https://github.com/RobotLocomotion/gtk-pod.git) +set(gtk_GIT_TAG cbcecf686ad17eba5949e297ea187126b1a06431) +set(gloptipoly_GIT_REPOSITORY https://github.com/RobotLocomotion/gloptipoly3.git) # todo: rename that repo +set(gloptipoly_GIT_TAG a3547a6811bf76c4e18f00b6bcbc187c6a7fd3d8) +set(gurobi_GIT_REPOSITORY https://github.com/RobotLocomotion/gurobi.git) +set(gurobi_GIT_TAG beb0a84a1bcca1eb81a1b87d9fa140f2134d97e9) +set(iris_GIT_REPOSITORY https://github.com/rdeits/iris-distro.git) +set(iris_GIT_TAG 13468e0ea38e72ffae030adaa31e3015ea5f3ce0) +set(lcm_GIT_REPOSITORY https://github.com/RobotLocomotion/lcm-pod.git) +if (WIN32) # then use the cmake branch of lcm + set(lcm_GIT_TAG f828ee126532ceb24f10a7ca74e5acc7c2093c12) +else() + set(lcm_GIT_TAG c537a9029b4b53fa7602acfc1467d93291fcc55e) +endif() +set(libbot_GIT_REPOSITORY https://github.com/RobotLocomotion/libbot.git) +set(libbot_GIT_TAG c8c251cf2fe0954e5c4954a3e7c1e7a43a882492) +set(mosek_GIT_REPOSITORY https://github.com/RobotLocomotion/mosek.git) +set(mosek_GIT_TAG a72594c4a7c8c5c026fd291148bcac76146634c2) +set(octomap_GIT_REPOSITORY https://github.com/RobotLocomotion/octomap-pod.git) +set(octomap_GIT_TAG 00b28215d19580f9e964bc5d126ce55a9253671a) +set(sedumi_GIT_REPOSITORY https://github.com/RobotLocomotion/sedumi.git) +set(sedumi_GIT_TAG afac8ea98f91007a3710d761efd514e10d0ad536) +set(snopt_GIT_REPOSITORY https://github.com/RobotLocomotion/snopt.git) +set(snopt_GIT_TAG d7abb603690f41970273643ebb6e173b0e6e452b) +set(spotless_GIT_REPOSITORY https://github.com/RobotLocomotion/spotless-pod.git) +set(spotless_GIT_TAG 4794910f66b0777a767a3912c05f6183eef23436) +set(yalmip_GIT_REPOSITORY https://github.com/RobotLocomotion/yalmip.git) +set(yalmip_GIT_TAG c071fb7b7193491f8eefadba3bfff26160ad6cd4) +set(xfoil_GIT_REPOSITORY https://github.com/RobotLocomotion/xfoil.git) +set(xfoil_GIT_TAG fde0a9368dd451c93604051fc5704e120073800c) + +foreach (proj ${EXTERNAL_PROJECTS}) + set(deps) + foreach(dep ${${proj}_dependencies}) + list(FIND EXTERNAL_PROJECTS ${dep} find_result) + if (${dep} STREQUAL "drake" OR NOT find_result EQUAL -1) + list(APPEND deps ${dep}) + endif() + endforeach() + + if (${proj} STREQUAL "drake") + if (NOT ${proj}_GIT_CLONE_DIR) + set(${proj}_GIT_CLONE_DIR "${PROJECT_SOURCE_DIR}/externals/${proj}") + endif() + if (NOT ${proj}_SOURCE_DIR) + set(${proj}_SOURCE_DIR ${${proj}_GIT_CLONE_DIR}) + endif() + + message(STATUS "Preparing to build ${proj} with dependencies: ${deps}") + + # separate download target so I can make the download-all custom command as recommended in: + # http://comments.gmane.org/gmane.comp.programming.tools.cmake.user/53002 + if (AUTO_UPDATE_EXTERNALS) + ExternalProject_Add(download-${proj} + DOWNLOAD_DIR ${${proj}_GIT_CLONE_DIR} + SOURCE_DIR ${${proj}_GIT_CLONE_DIR} + GIT_REPOSITORY ${${proj}_GIT_REPOSITORY} + GIT_TAG ${${proj}_GIT_TAG} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + else() + ExternalProject_Add(download-${proj} + DOWNLOAD_DIR ${${proj}_GIT_CLONE_DIR} + SOURCE_DIR ${${proj}_GIT_CLONE_DIR} + GIT_REPOSITORY ${${proj}_GIT_REPOSITORY} + GIT_TAG ${${proj}_GIT_TAG} + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + endif() + + # now the actual project + ExternalProject_Add(${proj} + SOURCE_DIR ${${proj}_SOURCE_DIR} + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_IN_SOURCE 1 + BUILD_COMMAND ${MAKE_COMMAND} BUILD_PREFIX=${CMAKE_INSTALL_PREFIX} BUILD_TYPE=${CMAKE_BUILD_TYPE} + INSTALL_COMMAND "" + DEPENDS download-${proj} ${deps} + # BUILD_ALWAYS 1 + ) + else() + ExternalProject_Add(${proj} + SOURCE_DIR ${${proj}_SOURCE_DIR} + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_IN_SOURCE 1 + BUILD_COMMAND ${MAKE_COMMAND} BUILD_PREFIX=${CMAKE_INSTALL_PREFIX} BUILD_TYPE=${CMAKE_BUILD_TYPE} + INSTALL_COMMAND "" + DEPENDS ${deps} + # BUILD_ALWAYS 1 + ) + endif(${proj} STREQUAL "drake") + + + # once we require cmake version >= 3.1, then we can zap this and just use the BUILD_ALWAYS flags above + ExternalProject_Add_Step(${proj} forceconfigure + COMMAND ${CMAKE_COMMAND} -E echo "Force configure of ${proj}" + DEPENDEES update + DEPENDERS configure + ALWAYS 1) + +endforeach() + + +# todo: add a custom target for release_filelist + +add_custom_target(download-all) +add_custom_target(clean-all) +add_custom_target(status) +set(PROJECT_LIST) +foreach (proj ${EXTERNAL_PROJECTS}) + if (NOT ${proj} STREQUAL "drake") + add_dependencies(download-all download-${proj}) + ExternalProject_Get_Property(download-${proj} SOURCE_DIR) + add_custom_target(status-${proj} + COMMAND ${GIT_EXECUTABLE} status + WORKING_DIRECTORY ${SOURCE_DIR}) + add_dependencies(status status-${proj}) + endif() + + ExternalProject_Get_Property(${proj} SOURCE_DIR) + add_custom_target(clean-${proj} + COMMAND ${MAKE_COMMAND} BUILD_PREFIX=${CMAKE_INSTALL_PREFIX} BUILD_TYPE=${CMAKE_BUILD_TYPE} clean + WORKING_DIRECTORY ${SOURCE_DIR}) + add_dependencies(clean-all clean-${proj}) + list(APPEND PROJECT_LIST ${SOURCE_DIR}) +endforeach() + +string(REPLACE ";" " " PROJECT_LIST "${PROJECT_LIST}") +add_custom_target(list-project-dirs COMMAND echo "${PROJECT_LIST}") + + + diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..bcd766ddacc9 --- /dev/null +++ b/Makefile @@ -0,0 +1,94 @@ + +BUILD_SYSTEM:=$(OS) +ifeq ($(BUILD_SYSTEM),Windows_NT) +BUILD_SYSTEM:=$(shell uname -o 2> uname.err || echo Windows_NT) # set to Cygwin if appropriate +else +BUILD_SYSTEM:=$(shell uname -s) +endif +BUILD_SYSTEM:=$(strip $(BUILD_SYSTEM)) + +# Figure out where to build the software. +# Use BUILD_PREFIX if it was passed in. +# If not, search up to four parent directories for a 'build' directory. +# Otherwise, use ./build. +ifeq ($(BUILD_SYSTEM), Windows_NT) +ifeq "$(BUILD_PREFIX)" "" +BUILD_PREFIX:=$(shell (for %%x in (. .. ..\.. ..\..\.. ..\..\..\..) do ( if exist %cd%\%%x\build ( echo %cd%\%%x\build & exit ) )) & echo %cd%\build ) +endif +# don't clean up and create build dir as I do in linux. instead create it during configure. +else +ifeq "$(BUILD_PREFIX)" "" +BUILD_PREFIX:=$(shell for pfx in ./ .. ../.. ../../.. ../../../..; do d=`pwd`/$$pfx/build;\ + if [ -d $$d ]; then echo $$d; exit 0; fi; done; echo `pwd`/build) +endif +# create the build directory if needed, and normalize its path name +BUILD_PREFIX:=$(shell mkdir -p $(BUILD_PREFIX) && cd $(BUILD_PREFIX) && echo `pwd`) +endif + +ifeq "$(BUILD_SYSTEM)" "Cygwin" + BUILD_PREFIX:=$(shell cygpath -m $(BUILD_PREFIX)) +endif + +# Default to a release build. If you want to enable debugging flags, run +# "make BUILD_TYPE=Debug" +ifeq "$(BUILD_TYPE)" "" + BUILD_TYPE="Release" +endif + +export MAKE +export MAKEFLAGS + +.PHONY: all +all: pod-build/Makefile + cmake --build pod-build --config $(BUILD_TYPE) + +pod-build/Makefile: + $(MAKE) configure + +.PHONY: options +options: configure +ifeq ($(OS),Windows_NT) + cmake-gui pod-build +else + ccmake pod-build +endif + +.PHONY: configure +configure: +# @echo "BUILD_SYSTEM: '$(BUILD_SYSTEM)'" + @echo "BUILD_PREFIX: $(BUILD_PREFIX)" + +# create the temporary build directory if needed +# create the lib directory if needed, so the pkgconfig gets installed to the right place +ifeq ($(BUILD_SYSTEM), Windows_NT) + @if not exist pod-build ( mkdir pod-build ) +else + @mkdir -p pod-build +endif + +# run CMake to generate and configure the build scripts + @cd pod-build && cmake $(CMAKE_FLAGS) -DCMAKE_INSTALL_PREFIX=$(BUILD_PREFIX) \ + -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) .. + +.PHONY: download-all +download-all: configure + cmake --build pod-build --config $(BUILD_TYPE) --target $@ + +.PHONY: clean +clean: +ifeq ($(BUILD_SYSTEM),Windows_NT) + rd /s pod-build + rd /s build +else + -if [ -e pod-build/install_manifest.txt ]; then rm -f `cat pod-build/install_manifest.txt`; fi + -if [ -d pod-build ]; then cmake --build pod-build --target clean-all; fi #rm -rf pod-build; fi + -rm -rf build +endif + +# other (custom) targets are passed through to the cmake-generated Makefile +%:: + cmake --build pod-build --config $(BUILD_TYPE) --target $@ + +# Default to a less-verbose build. If you want all the gory compiler output, +# run "make VERBOSE=1" +$(VERBOSE).SILENT: diff --git a/addpath_pods.m b/addpath_pods.m new file mode 100644 index 000000000000..531d01d6e760 --- /dev/null +++ b/addpath_pods.m @@ -0,0 +1,13 @@ +function addpath_pods +% does the pod thing - looking up to 4 directories above for a folder named +% build (with /matlab) and then adds it to the path + +pfx=''; +for i=1:4 + if exist(fullfile(pfx,'build','matlab'),'file') + disp(['Adding ', fullfile(pwd,pfx,'build','matlab'), ' to the matlab path']); + addpath(fullfile(pwd,pfx,'build','matlab')); + break; + end + pfx = fullfile('..',pfx); +end diff --git a/install_prereqs.sh b/install_prereqs.sh new file mode 100755 index 000000000000..e3d6387f265b --- /dev/null +++ b/install_prereqs.sh @@ -0,0 +1,30 @@ +#!/bin/bash + + +case $1 in + ("homebrew") + brew install cmake pkg-config gtk+ ;; + ("macports") + port install cmake gtk2 ;; + ("ubuntu") + apt-get install cmake openjdk-6-jdk build-essential ;; + ("cygwin") + cygwin-setup -q -P make pkg-config ;; + (*) + echo "Usage: ./install_prereqs.sh package_manager" + echo "where package_manager is one of the following: " + echo " homebrew" + echo " macports" + echo " ubuntu" + echo " cygwin" + exit 1 ;; +esac + +make download-all +SUBDIRS=`make list-project-dirs` +for subdir in $SUBDIRS; do # note this will also catch `Built target list-project-dirs`, but it's harmless + if [ -f $subdir/install_prereqs.sh ]; then + echo "installing prereqs for $subdir" + ( cd $subdir; ./install_prereqs.sh $1 || true ) + fi +done