diff --git a/.gitignore b/.gitignore index 1cd3e01777..8fb2dcfc8f 100644 --- a/.gitignore +++ b/.gitignore @@ -71,5 +71,6 @@ tools/docker/export .idea/* .idea/ build/ +cache/ **/.vscode/* .DS_Store diff --git a/cmake/Makefile b/cmake/Makefile new file mode 100644 index 0000000000..c53e2ed176 --- /dev/null +++ b/cmake/Makefile @@ -0,0 +1,132 @@ +help: + @echo "usage:" + @echo "make docker: generate docker images" + @echo "make configure: cmake configure" + @echo "make build: cmake build" + @echo "make test: run unit tests" + @echo "make install: cmake install" + @echo "make test_install: configure a sample project against an installation" + @echo "make clean: call cmake \"make clean\"" + @echo "make distclean: clean and also remove all docker images" + +# Need to add cmd_distro to PHONY otherwise target are ignored since they don't +# contain recipe (using FORCE don't work here) +.PHONY: help all +all: build + +PROJECT := ortools +#UID := $(shell id -u) +#GID := $(shell id -g) +#DOCKER_DEVEL_CMD := docker run --rm -it -v ${PWD}:/project -w /project --user ${UID}:${GID} +DOCKER_DEVEL_CMD := docker run --rm -it -v ${PWD}:/project -w /project +DOCKER_INSTALL_CMD := docker run --rm -it -v ${PWD}/cmake/sample:/project -w /project + +# $* stem +# $< first prerequist +# $@ target name + +# DOCKER +.PHONY: docker docker_alpine docker_ubuntu +docker: docker_alpine docker_ubuntu +docker_alpine: cache/alpine/docker_devel.tar +docker_ubuntu: cache/ubuntu/docker_devel.tar +cache/%/docker_devel.tar: cmake/docker/%/Dockerfile cmake/docker/%/setup.sh + mkdir -p cache/$* + @docker image rm -f ${PROJECT}_$*:devel 2>/dev/null + docker build --no-cache -t ${PROJECT}_$*:devel -f $< cmake/docker/$* + docker save ${PROJECT}_$*:devel -o $@ + +# DOCKER BASH +.PHONY: bash_alpine bash_ubuntu +bash_alpine: cache/alpine/docker_devel.tar + ${DOCKER_DEVEL_CMD} ${PROJECT}_alpine:devel /bin/sh +bash_ubuntu: cache/ubuntu/docker_devel.tar + ${DOCKER_DEVEL_CMD} ${PROJECT}_ubuntu:devel /bin/bash + +# CONFIGURE +.PHONY: configure configure_alpine configure_ubuntu +configure: configure_alpine configure_ubuntu +configure_alpine: cache/alpine/configure.log +configure_ubuntu: cache/ubuntu/configure.log +cache/%/configure.log: cache/%/docker_devel.tar \ + CMakeLists.txt cmake/external/CMakeLists.txt ortools/*/CMakeLists.txt \ + cmake/*.cmake cmake/*Config.cmake.in patches + @docker load -i $< + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "cmake -H. -Bcache/$*" + @date > $@ + +# BUILD +.PHONY: build build_alpine build_ubuntu +build: build_alpine build_ubuntu +build_alpine: cache/alpine/build.log +build_ubuntu: cache/ubuntu/build.log +cache/%/build.log: cache/%/configure.log ortools examples + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "cmake --build cache/$* --target all" + @date > $@ + +# TEST +.PHONY: test test_alpine test_ubuntu +test: test_ubuntu +test_alpine: cache/alpine/test.log +test_ubuntu: cache/ubuntu/test.log +cache/%/test.log: cache/%/build.log + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "cd cache/$* && ctest --output-on-failure" + @date > $@ + +# INSTALL +.PHONY: install install_alpine install_ubuntu +install: install_ubuntu +install_alpine: cache/alpine/install.log +install_ubuntu: cache/ubuntu/install.log +cache/%/install.log: cmake/docker/%/InstallDockerfile cache/%/build.log + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "cmake --build cache/$* --target install -- DESTDIR=install" + @docker image rm -f ${PROJECT}_$*:install 2>/dev/null + docker build --no-cache -t ${PROJECT}_$*:install -f $< . + docker save ${PROJECT}_$*:install -o cache/$*/docker_install.tar + @date > $@ + +# DOCKER BASH INSTALL +.PHONY: bash_install_alpine bash_install_ubuntu +bash_install_alpine: cache/alpine/install.log + @docker load -i cache/alpine/docker_install.tar + ${DOCKER_INSTALL_CMD} ${PROJECT}_alpine:install /bin/sh +bash_install_ubuntu: cache/ubuntu/install.log + @docker load -i cache/ubuntu/docker_install.tar + ${DOCKER_INSTALL_CMD} ${PROJECT}_ubuntu:install /bin/bash + +# TEST INSTALL of ProjectConfigs.cmake +.PHONY: test_install test_install_alpine bash_isntall_ubuntu +test_install: test_install_alpine test_install_ubuntu +test_install_alpine: cache/alpine/test_install.log +test_install_ubuntu: cache/ubuntu/test_install.log +cache/%/test_install.log: cache/%/install.log cmake/sample + @docker load -i cache/$*/docker_install.tar + ${DOCKER_INSTALL_CMD} ${PROJECT}_$*:install /bin/sh -c "cmake -H. -B/cache; cmake --build /cache; cmake --build /cache --target test -- ARGS=-V" + @date > $@ + +# CLEAN +.PHONY: clean clean_alpine clean_ubuntu +clean: clean_alpine clean_ubuntu +clean_alpine: clean-alpine +clean_ubuntu: clean-ubuntu +clean-%:: cache/%/docker_devel.tar + @docker load -i $< + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "cmake --build cache/$* --target clean" + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "rm -rf cache/$*/install" + @rm -f cache/$*/test.log + @rm -f cache/$*/build.log + @rm -f cache/$*/configure.log + @rm -f cache/$*/install.log + @rm -f cache/$*/test_install.log + +# DISTCLEAN +.PHONY: distclean distclean_alpine distclean_ubuntu +distclean: distclean_alpine distclean_ubuntu + docker image prune -f + rmdir cache +distclean_alpine: distclean-alpine +distclean_ubuntu: distclean-ubuntu +distclean-%:: + ${DOCKER_DEVEL_CMD} ${PROJECT}_$*:devel /bin/sh -c "rm -rf cache/$*" + docker image rm -f ${PROJECT}_$*:devel 2>/dev/null + docker image rm -f ${PROJECT}_$*:install 2>/dev/null diff --git a/cmake/docker/alpine/Dockerfile b/cmake/docker/alpine/Dockerfile new file mode 100644 index 0000000000..b41736492f --- /dev/null +++ b/cmake/docker/alpine/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest +LABEL maintainer="corentinl@google.com" + +ADD setup.sh . +RUN ./setup.sh diff --git a/cmake/docker/alpine/InstallDockerfile b/cmake/docker/alpine/InstallDockerfile new file mode 100644 index 0000000000..6f37b712cd --- /dev/null +++ b/cmake/docker/alpine/InstallDockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest +LABEL maintainer="corentinl@google.com" + +RUN apk add --no-cache git build-base cmake +COPY cache/alpine/install / diff --git a/cmake/docker/alpine/setup.sh b/cmake/docker/alpine/setup.sh new file mode 100755 index 0000000000..165284bc72 --- /dev/null +++ b/cmake/docker/alpine/setup.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +set -x +apk add --no-cache git build-base linux-headers cmake swig \ + python3-dev py3-virtualenv +python3 -m pip install wheel diff --git a/cmake/docker/ubuntu/Dockerfile b/cmake/docker/ubuntu/Dockerfile new file mode 100644 index 0000000000..9a178d92d2 --- /dev/null +++ b/cmake/docker/ubuntu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:latest +LABEL maintainer="corentinl@google.com" + +ADD setup.sh . +RUN ./setup.sh && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/cmake/docker/ubuntu/InstallDockerfile b/cmake/docker/ubuntu/InstallDockerfile new file mode 100644 index 0000000000..ce0169c478 --- /dev/null +++ b/cmake/docker/ubuntu/InstallDockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:devel +LABEL maintainer="corentinl@google.com" + +RUN apt-get update -qq && \ +apt-get install -qq build-essential cmake && \ +apt-get clean && \ +rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +COPY cache/ubuntu/install / diff --git a/cmake/docker/ubuntu/setup.sh b/cmake/docker/ubuntu/setup.sh new file mode 100755 index 0000000000..3da5a243cc --- /dev/null +++ b/cmake/docker/ubuntu/setup.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -x +apt-get update -qq +apt-get install -qq git wget build-essential swig python3-dev python3-pip +python3 -m pip install virtualenv +wget https://cmake.org/files/v3.10/cmake-3.10.2-Linux-x86_64.sh && \ +chmod a+x cmake-3.10.2-Linux-x86_64.sh && \ +./cmake-3.10.2-Linux-x86_64.sh --prefix=/usr/local/ --skip-license && \ +rm cmake-3.10.2-Linux-x86_64.sh + diff --git a/cmake/sample/CMakeLists.txt b/cmake/sample/CMakeLists.txt new file mode 100644 index 0000000000..2c7c47c0fb --- /dev/null +++ b/cmake/sample/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +project(Sample VERSION 1.0 LANGUAGES CXX) + +find_package(ortools CONFIG REQUIRED) + +add_executable(sample main.cpp) +target_link_libraries(sample PRIVATE ortools::ortools) + +include(CTest) +if(BUILD_TESTING) + add_test(NAME sample_UT COMMAND sample) +endif() diff --git a/cmake/sample/main.cpp b/cmake/sample/main.cpp new file mode 100644 index 0000000000..d2dbe41d81 --- /dev/null +++ b/cmake/sample/main.cpp @@ -0,0 +1,52 @@ +#include +#include +#include + +namespace operations_research { +void RunLinearExample( + MPSolver::OptimizationProblemType optimization_problem_type) { + MPSolver solver("LinearExample", optimization_problem_type); + const double infinity = solver.infinity(); + // x and y are non-negative variables. + MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); + // Objective function: 3x + 4y. + MPObjective* const objective = solver.MutableObjective(); + objective->SetCoefficient(x, 3); + objective->SetCoefficient(y, 4); + objective->SetMaximization(); + // x + 2y <= 14. + MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 14.0); + c0->SetCoefficient(x, 1); + c0->SetCoefficient(y, 2); + + // 3x - y >= 0. + MPConstraint* const c1 = solver.MakeRowConstraint(0.0, infinity); + c1->SetCoefficient(x, 3); + c1->SetCoefficient(y, -1); + + // x - y <= 2. + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 2.0); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, -1); + std::cout << "Number of variables = " << solver.NumVariables() << std::endl; + std::cout << "Number of constraints = " << solver.NumConstraints() << std::endl; + solver.Solve(); + // The value of each variable in the solution. + std::cout << "Solution:" << std::endl + << "x = " << x->solution_value() << std::endl + << "y = " << y->solution_value() << std::endl; + + // The objective value of the solution. + std::cout << "Optimal objective value = " << objective->Value() << std::endl; +} + +void RunExample() { + RunLinearExample(MPSolver::GLOP_LINEAR_PROGRAMMING); +} +} // namespace operations_research + +int main(int argc, char** argv) { + operations_research::RunExample(); + return 0; +}