Skip to content

Commit

Permalink
Conan support
Browse files Browse the repository at this point in the history
  • Loading branch information
tttapa committed Feb 22, 2024
1 parent 2666c9e commit 53269bc
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 18 deletions.
6 changes: 2 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

cmake_minimum_required(VERSION 3.17)
project(QPALM-dev)
enable_testing()
include(CTest)

# Add coverage target
option(QPALM_WITH_COVERAGE
Expand Down Expand Up @@ -41,8 +41,6 @@ if (QPALM_WITH_EXAMPLES)
endif()

# Unit tests
option(QPALM_WITH_TESTS
"Build the unit tests" On)
if (QPALM_WITH_TESTS)
if (BUILD_TESTING)
add_subdirectory(test)
endif()
2 changes: 1 addition & 1 deletion LADEL
6 changes: 5 additions & 1 deletion QPALM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ function(add_ladel)
set(LADEL_WITH_MEX ${QPALM_WITH_MEX})
add_subdirectory(../LADEL/LADEL LADEL EXCLUDE_FROM_ALL)
endfunction()
add_ladel()
find_package(LADEL QUIET)
if (NOT LADEL_FOUND)
message(STATUS "Using included LADEL")
add_ladel()
endif()

# QPALM C library
add_library(qpalm-headers INTERFACE)
Expand Down
2 changes: 1 addition & 1 deletion QPALM/cmake/Config.cmake.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)
find_dependency(ladel)
find_dependency(LADEL)

include ("${CMAKE_CURRENT_LIST_DIR}/QPALMTargets.cmake")
3 changes: 0 additions & 3 deletions QPALM/interfaces/julia/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@ target_compile_definitions(qpalm_jll
target_link_libraries(qpalm_jll PUBLIC qpalm-obj)
target_link_libraries(qpalm_jll PRIVATE qpalm_lax_warnings)
if (CMAKE_SYSTEM_NAME MATCHES "Linux") # Make sure LADEL is included privately
# target_link_options(qpalm_jll PRIVATE
# "LINKER:--exclude-libs,$<TARGET_FILE_BASE_NAME:ladel>")
target_link_options(qpalm_jll PRIVATE
"LINKER:--exclude-libs,ALL")
endif()

# Install the QPALM shared library Julia module
include(GNUInstallDirs)
install(TARGETS qpalm_jll
EXCLUDE_FROM_ALL
COMPONENT julia_modules
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
4 changes: 4 additions & 0 deletions QPALM/interfaces/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ install(TARGETS _qpalm
EXCLUDE_FROM_ALL
COMPONENT python_modules
DESTINATION ${PY_BUILD_CMAKE_MODULE_NAME})
# Standard installation
install(TARGETS _qpalm
COMPONENT python
DESTINATION ${CMAKE_INSTALL_LIBDIR}/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages/${PY_BUILD_CMAKE_MODULE_NAME})

# Strip and install debug information
set(DEBUG_FILE "$<TARGET_FILE_NAME:_qpalm>.debug")
Expand Down
14 changes: 7 additions & 7 deletions QPALM/interfaces/python/cmake/QueryPythonForPybind11.cmake
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
option(USE_GLOBAL_PYBIND11 "Don't query Python to find pybind11" Off)
mark_as_advanced(USE_GLOBAL_PYBIND11)

# Find Python
if (CMAKE_CROSSCOMPILING AND FALSE)
find_package(Python3 REQUIRED COMPONENTS Development.Module)
else()
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
endif()

# First tries to find Python 3, then tries to import the pybind11 module to
# query the CMake config location, and finally imports pybind11 using
# find_package(pybind11 REQUIRED CONFIG CMAKE_FIND_ROOT_PATH_BOTH).
function(find_pybind11_python_first)

# Find Python
if (CMAKE_CROSSCOMPILING AND FALSE)
find_package(Python3 REQUIRED COMPONENTS Development.Module)
else()
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
endif()

# Tweak extension suffix and debug ABI when cross-compiling
if (CMAKE_CROSSCOMPILING)
if (NOT PY_BUILD_EXT_SUFFIX AND DEFINED TOOLCHAIN_Python3_EXT_SUFFIX)
Expand Down
95 changes: 95 additions & 0 deletions conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import os

from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout
from conan.tools.build import can_run


class QPALMRecipe(ConanFile):
name = "qpalm"
version = "1.2.2"

# Optional metadata
license = "LGPLv3"
author = "Pieter P <[email protected]>"
url = "https://github.com/kul-optec/QPALM"
description = "Proximal Augmented Lagrangian method for Quadratic Programs"
topics = ("optimization", "quadratic-program", "qp", "alm")

# Binary configuration
settings = "os", "compiler", "build_type", "arch"
bool_qpalm_options = {
"with_cxx": True,
"with_python": False,
"with_julia": False,
"with_fortran": False,
}
options = {
"shared": [True, False],
"fPIC": [True, False],
} | {k: [True, False] for k in bool_qpalm_options}
default_options = {
"shared": False,
"fPIC": True,
} | bool_qpalm_options

# Sources are located in the same place as this recipe, copy them to the recipe
exports_sources = (
"CMakeLists.txt",
"QPALM/*",
"LADEL/*",
"examples/*",
"test/*",
"LICENSE",
"README.md",
)

generators = ("CMakeDeps",)

def requirements(self):
self.requires("ladel/0.0.1", transitive_headers=True)
self.test_requires("gtest/1.11.0")
if self.options.with_cxx:
self.requires("eigen/3.4.0", transitive_headers=True)
if self.options.with_python:
self.requires("pybind11/2.11.1")

def config_options(self):
if self.settings.get_safe("os") == "Windows":
self.options.rm_safe("fPIC")

def validate(self):
if self.options.with_python and not self.options.with_cxx:
msg = "Python interface requires C++. Set 'with_cxx=True'."
raise ConanInvalidConfiguration(msg)

def layout(self):
cmake_layout(self)

def generate(self):
tc = CMakeToolchain(self)
tc.variables["QPALM_WITH_EXAMPLES"] = False
for k in self.bool_qpalm_options:
value = getattr(self.options, k, None)
if value is not None and value.value is not None:
tc.variables["QPALM_" + k.upper()] = bool(value)
if self.options.with_python:
tc.variables["USE_GLOBAL_PYBIND11"] = True
if can_run(self):
tc.variables["QPALM_FORCE_TEST_DISCOVERY"] = True
tc.generate()

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
cmake.test()

def package(self):
cmake = CMake(self)
cmake.install()

def package_info(self):
self.cpp_info.set_property("cmake_find_mode", "none")
self.cpp_info.builddirs.append(os.path.join("lib", "cmake", "QPALM"))
5 changes: 4 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@ if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.21)
COMMAND_EXPAND_LISTS)
endif()

gtest_discover_tests(tests DISCOVERY_TIMEOUT 60)
option(QPALM_FORCE_TEST_DISCOVERY Off)
if (NOT CMAKE_CROSSCOMPILING OR QPALM_FORCE_TEST_DISCOVERY)
gtest_discover_tests(tests DISCOVERY_TIMEOUT 60)
endif()
add_executable(QPALM::tests ALIAS tests)
7 changes: 7 additions & 0 deletions test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.24)
project(qpalm_test_package C)

find_package(QPALM REQUIRED)
add_executable(example src/example.c)
target_link_libraries(example PRIVATE QPALM::qpalm)
install(TARGETS example)
26 changes: 26 additions & 0 deletions test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os

from conan import ConanFile
from conan.tools.cmake import CMake, cmake_layout
from conan.tools.build import can_run


class QPALMTest(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeDeps", "CMakeToolchain"

def requirements(self):
self.requires(self.tested_reference_str)

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def layout(self):
cmake_layout(self)

def test(self):
if can_run(self):
cmd = os.path.join(self.cpp.build.bindir, "example")
self.run(cmd, env="conanrun")
99 changes: 99 additions & 0 deletions test_package/src/example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include <qpalm.h>
#include <stdio.h>

#define N 2
#define M 3
#define ANZMAX 4
#define QNZMAX 2

#define TRUE 1
#define FALSE 0

c_float *random_vector(c_int n) {
c_float *X = (c_float *)qpalm_calloc(n, sizeof(c_float));
for (int i = 0; i < n; i++)
X[i] = (c_float)10 * rand() / (c_float)RAND_MAX;
return X;
}

c_float *constant_vector(c_float c, c_int n) {
c_float *X = (c_float *)qpalm_calloc(n, sizeof(c_float));
for (int i = 0; i < n; i++)
X[i] = c;
return X;
}
int main() {

// Load problem data
c_int n = N;
c_int m = M;

// Problem settings
QPALMSettings *settings =
(QPALMSettings *)qpalm_malloc(sizeof(QPALMSettings));

// Structures
QPALMWorkspace *work; // Solver workspace
QPALMData *data; // Problem matrices

// Populate data
srand(12345);
data = (QPALMData *)qpalm_malloc(sizeof(QPALMData));
data->n = n;
data->m = m;
data->q = random_vector(data->n);
data->c = 0;
data->bmin = constant_vector(-2, data->m);
data->bmax = constant_vector(2, data->m);

solver_sparse *A, *Q;
A = ladel_sparse_alloc(M, N, ANZMAX, UNSYMMETRIC, TRUE, FALSE);
Q = ladel_sparse_alloc(N, N, QNZMAX, UPPER, TRUE, FALSE);

// clang-format off
A->x[0] = 1; A->x[1] = 1; A->x[2] = 1; A->x[3] = 1;
A->p[0] = 0; A->p[1] = 2; A->p[2] = 4;
A->i[0] = 0; A->i[1] = 2; A->i[2] = 1; A->i[3] = 2;
Q->x[0] = 1.0; Q->x[1] = 1.5;
Q->p[0] = 0; Q->p[1] = 1; Q->p[2] = 2;
Q->i[0] = 0; Q->i[1] = 1;
// clang-format on
data->A = A;
data->Q = Q;

// Define Solver settings as default
qpalm_set_default_settings(settings);

// Setup workspace
work = qpalm_setup(data, settings);

// Solve Problem
qpalm_solve(work);

printf("Solver status: ");
puts(work->info->status);
printf("Iter: %d\n", (int)work->info->iter);
printf("Iter Out: %d\n", (int)work->info->iter_out);
printf("Solution:");
for (c_int i = 0; i < n; i++)
printf(" %.10f", work->solution->x[i]);
printf("\n");
#ifdef QPALM_TIMING
printf("Setup time: %f\n", work->info->setup_time);
printf("Solve time: %f\n", work->info->solve_time);
printf("Run time: %f\n", work->info->run_time);
#endif

// Clean workspace
ladel_sparse_free(data->Q);
ladel_sparse_free(data->A);

qpalm_cleanup(work);
qpalm_free(data->q);
qpalm_free(data->bmin);
qpalm_free(data->bmax);
qpalm_free(data);
qpalm_free(settings);

return 0;
}

0 comments on commit 53269bc

Please sign in to comment.