From 4385531e9ec0faad341720cee8ece6d613321a0c Mon Sep 17 00:00:00 2001 From: Zhe Li Date: Wed, 8 Mar 2023 11:05:59 -0500 Subject: [PATCH] osqp: add recipe --- recipes/osqp/all/conandata.yml | 4 + recipes/osqp/all/conanfile.py | 93 +++++++++++++++++++ recipes/osqp/all/test_package/CMakeLists.txt | 8 ++ recipes/osqp/all/test_package/conanfile.py | 27 ++++++ .../osqp/all/test_package/test_package.cpp | 69 ++++++++++++++ .../osqp/all/test_v1_package/CMakeLists.txt | 8 ++ recipes/osqp/all/test_v1_package/conanfile.py | 19 ++++ recipes/osqp/config.yml | 3 + 8 files changed, 231 insertions(+) create mode 100644 recipes/osqp/all/conandata.yml create mode 100644 recipes/osqp/all/conanfile.py create mode 100644 recipes/osqp/all/test_package/CMakeLists.txt create mode 100644 recipes/osqp/all/test_package/conanfile.py create mode 100644 recipes/osqp/all/test_package/test_package.cpp create mode 100644 recipes/osqp/all/test_v1_package/CMakeLists.txt create mode 100644 recipes/osqp/all/test_v1_package/conanfile.py create mode 100644 recipes/osqp/config.yml diff --git a/recipes/osqp/all/conandata.yml b/recipes/osqp/all/conandata.yml new file mode 100644 index 00000000000000..905d89304cb35d --- /dev/null +++ b/recipes/osqp/all/conandata.yml @@ -0,0 +1,4 @@ +sources: + "0.6.2": + url: "https://github.com/osqp/osqp/releases/download/v0.6.2/complete_sources.tar.gz" + sha256: "0a7ade2fa19f13e13bc12f6ea0046ef764049023efb4997a4e72a76534f623ec" diff --git a/recipes/osqp/all/conanfile.py b/recipes/osqp/all/conanfile.py new file mode 100644 index 00000000000000..82b911739959a9 --- /dev/null +++ b/recipes/osqp/all/conanfile.py @@ -0,0 +1,93 @@ +from conan import ConanFile +from conan.tools.files import get, copy, rm, rmdir +from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout +import os + +required_conan_version = ">=1.53.0" + +class PackageConan(ConanFile): + name = "osqp" + description = "The OSQP (Operator Splitting Quadratic Program) solver is a numerical optimization package." + license = "Apache-2.0" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://osqp.org/" + topics = ("machine-learning", "control", "optimization", "svm", "solver", "lasso", "portfolio-optimization", + "numerical-optimization", "quadratic-programming", "convex-optimization", "model-predictive-control") + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + } + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + self.settings.rm_safe("compiler.libcxx") + self.settings.rm_safe("compiler.cppstd") + + def layout(self): + cmake_layout(self, src_folder="src") + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + tc.variables['UNITTESTS'] = not self.conf.get("tools.build:skip_test", default=True, check_type=bool) + tc.variables["PRINTING"] = True + tc.variables["PROFILING"] = True + tc.variables["CTRLC"] = True + tc.variables["DFLOAT"] = False + tc.variables["DLONG"] = True + tc.variables["COVERAGE"] = False + tc.variables["ENABLE_MKL_PARDISO"] = True + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, pattern="LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) + cmake = CMake(self) + cmake.install() + if self.settings.os == "Windows": + copy(self, "*.dll", dst=os.path.join(self.package_folder, "lib"), src=os.path.join(self.package_folder, "bin")) + + if self.options.shared: + rm(self, "*.a", os.path.join(self.package_folder, "lib")) + rm(self, "*.lib", os.path.join(self.package_folder, "lib")) + else: + rm(self, "*.so", os.path.join(self.package_folder, "lib")) + rm(self, "*.dylib", os.path.join(self.package_folder, "lib")) + rm(self, "*.dll", os.path.join(self.package_folder, "lib")) + + rmdir(self, os.path.join(self.package_folder, "bin")) + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + rmdir(self, os.path.join(self.package_folder, "include", "qdldl")) + rm(self, "*qdldl.*", os.path.join(self.package_folder, "lib")) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "osqp") + self.cpp_info.set_property("cmake_target_name", "osqp::osqp") + self.cpp_info.libs = ["osqp"] + + if self.settings.os in ["Linux", "FreeBSD"]: + self.cpp_info.system_libs.append("m") + self.cpp_info.system_libs.append("rt") + self.cpp_info.system_libs.append("dl") + + # TODO: to remove in conan v2 once cmake_find_package_* generators removed + self.cpp_info.filenames["cmake_find_package"] = "osqp" + self.cpp_info.filenames["cmake_find_package_multi"] = "osqp" + self.cpp_info.names["cmake_find_package"] = "osqp" + self.cpp_info.names["cmake_find_package_multi"] = "osqp" diff --git a/recipes/osqp/all/test_package/CMakeLists.txt b/recipes/osqp/all/test_package/CMakeLists.txt new file mode 100644 index 00000000000000..e2ad808df3b716 --- /dev/null +++ b/recipes/osqp/all/test_package/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.8) + +project(test_package CXX) + +find_package(osqp REQUIRED CONFIG) + +add_executable(${PROJECT_NAME} test_package.cpp) +target_link_libraries(${PROJECT_NAME} PRIVATE osqp::osqp) diff --git a/recipes/osqp/all/test_package/conanfile.py b/recipes/osqp/all/test_package/conanfile.py new file mode 100644 index 00000000000000..1111583fea732f --- /dev/null +++ b/recipes/osqp/all/test_package/conanfile.py @@ -0,0 +1,27 @@ +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import cmake_layout, CMake +import os + + +# It will become the standard on Conan 2.x +class TestPackageConan(ConanFile): + settings = "os", "arch", "compiler", "build_type" + generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv" + test_type = "explicit" + + def requirements(self): + self.requires(self.tested_reference_str) + + def layout(self): + cmake_layout(self) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package") + self.run(bin_path, env="conanrun") diff --git a/recipes/osqp/all/test_package/test_package.cpp b/recipes/osqp/all/test_package/test_package.cpp new file mode 100644 index 00000000000000..c966b1083c67d3 --- /dev/null +++ b/recipes/osqp/all/test_package/test_package.cpp @@ -0,0 +1,69 @@ +/** + * Below is a demo copied from an upstream example code, + * It shows how to setup and solve an optimization problem. + * Source code: https://github.com/osqp/osqp/blob/master/examples/osqp_demo.c + * Problem definition: https://osqp.org/docs/examples/setup-and-solve.html +*/ +#include "osqp/osqp.h" + + +int main(void) { + // Load problem data + c_float P_x[3] = {4.0, 1.0, 2.0, }; + c_int P_nnz = 3; + c_int P_i[3] = {0, 0, 1, }; + c_int P_p[3] = {0, 1, 3, }; + c_float q[2] = {1.0, 1.0, }; + c_float A_x[4] = {1.0, 1.0, 1.0, 1.0, }; + c_int A_nnz = 4; + c_int A_i[4] = {0, 1, 0, 2, }; + c_int A_p[3] = {0, 2, 4, }; + c_float l[3] = {1.0, 0.0, 0.0, }; + c_float u[3] = {1.0, 0.7, 0.7, }; + c_int n = 2; + c_int m = 3; + + // Exitflag + c_int exitflag = 0; + + // Workspace structures + OSQPWorkspace *work; + OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings)); + OSQPData *data = (OSQPData *)c_malloc(sizeof(OSQPData)); + + // Populate data + if (data) { + data->n = n; + data->m = m; + data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p); + data->q = q; + data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p); + data->l = l; + data->u = u; + } + + // Define solver settings as default + if (settings) { + osqp_set_default_settings(settings); + settings->alpha = 1.0; // Change alpha parameter + } + + // Setup workspace + exitflag = osqp_setup(&work, data, settings); + + // Solve Problem + osqp_solve(work); + + // Cleanup + osqp_cleanup(work); + if (data) { + if (data->A) c_free(data->A); + if (data->P) c_free(data->P); + c_free(data); + } + if (settings) c_free(settings); + + return exitflag; + + return EXIT_SUCCESS; +} diff --git a/recipes/osqp/all/test_v1_package/CMakeLists.txt b/recipes/osqp/all/test_v1_package/CMakeLists.txt new file mode 100644 index 00000000000000..925ecbe19e448d --- /dev/null +++ b/recipes/osqp/all/test_v1_package/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.1) +project(test_package) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup(TARGETS) + +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package/ + ${CMAKE_CURRENT_BINARY_DIR}/test_package/) diff --git a/recipes/osqp/all/test_v1_package/conanfile.py b/recipes/osqp/all/test_v1_package/conanfile.py new file mode 100644 index 00000000000000..c492184eec19c2 --- /dev/null +++ b/recipes/osqp/all/test_v1_package/conanfile.py @@ -0,0 +1,19 @@ +from conans import ConanFile, CMake +from conan.tools.build import cross_building +import os + + +# legacy validation with Conan 1.x +class TestPackageV1Conan(ConanFile): + settings = "os", "arch", "compiler", "build_type" + generators = "cmake", "cmake_find_package_multi" + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if not cross_building(self): + bin_path = os.path.join("bin", "test_package") + self.run(bin_path, run_environment=True) diff --git a/recipes/osqp/config.yml b/recipes/osqp/config.yml new file mode 100644 index 00000000000000..a09c617182ab2d --- /dev/null +++ b/recipes/osqp/config.yml @@ -0,0 +1,3 @@ +versions: + "0.6.2": + folder: all