Skip to content

Commit

Permalink
Merge pull request #16 from Ultimaker/CURA-7924_sip_cmake_build
Browse files Browse the repository at this point in the history
Cura 7924 sip cmake build
  • Loading branch information
nallath authored Feb 28, 2022
2 parents 3533c8c + 59a58d3 commit 207c521
Show file tree
Hide file tree
Showing 11 changed files with 346 additions and 266 deletions.
87 changes: 41 additions & 46 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,54 @@
# pynest2d is released under the terms of the LGPLv3 or higher.

project(pynest2d)
cmake_minimum_required(VERSION 3.6) # Lowest version it's been tested with.
cmake_minimum_required(VERSION 3.18) # Lowest version it's been tested with.

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")

# Requirements.
# FIXME: Remove the code for CMake <3.12 once we have switched over completely.
# FindPython3 is a new module since CMake 3.12. It deprecates FindPythonInterp and FindPythonLibs.
if(${CMAKE_VERSION} VERSION_LESS 3.12)
# FIXME: Use FindPython3 to find Python, new in CMake 3.12.
# However currently on our CI server it finds the wrong Python version and then doesn't find the headers.
find_package(PythonInterp 3.5 REQUIRED)
find_package(PythonLibs 3.5 REQUIRED)

else()
# Use FindPython3 for CMake >=3.12
find_package(Python3 3.5 REQUIRED COMPONENTS Interpreter Development)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(NOT DEFINED Python_VERSION)
set(Python_VERSION
3.10
CACHE STRING "Python Version" FORCE)
message(STATUS "Setting Python version to ${Python_VERSION}. Set Python_VERSION if you want to compile against an other version.")
endif()
if(APPLE)
set(Python_FIND_FRAMEWORK NEVER)
endif()
find_package(Python ${Python_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development)
message(STATUS "Linking and building ${project_name} against Python ${Python_VERSION}")

find_package(SIP REQUIRED 6.5.0)

find_package(SIP REQUIRED) # To create Python bindings.
find_package(libnest2d REQUIRED) # The library we're creating bindings for.
find_package(Clipper REQUIRED) # Dependency of libnest2d.
find_package(NLopt REQUIRED) # Dependency of libnest2d.
find_package(Boost REQUIRED) # Dependency of libnest2d.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLIBNEST2D_GEOMETRIES_clipper -DLIBNEST2D_OPTIMIZERS_nlopt -DLIBNEST2D_THREADING_std") # Tell libnest2d to use Clipper and NLopt, and standard threads.

# Some build options.
add_library(pynest2d INTERFACE)

target_include_directories(pynest2d
INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/>
)

# Use C++17 Standard
message(STATUS "Setting C++17 support with extensions off and standard required")
set(CMAKE_CXX_STANDARD 17)
if(APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
if(UNIX)
# Want to be able to move symbols from the Clipper library.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
endif()
if(NOT DEFINED LIB_SUFFIX)
set(LIB_SUFFIX "")
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
target_compile_features(pynest2d INTERFACE cxx_std_17)

if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
if (APPLE)
message(STATUS "Compiling ${project_name} against libc++")
target_compile_options(pynest2d INTERFACE "-stdlib=libc++")
endif()
endif()

# Building and linking.
set(SIP_EXTRA_FILES_DEPEND
src/BottomLeftConfig.sip
src/Box.sip
src/Circle.sip
src/DJDHeuristicConfig.sip
src/Item.sip
src/ItemGroup.sip
src/NfpConfig.sip
src/Point.sip
src/Rectangle.sip
src/String.sip
)

set(SIP_EXTRA_OPTIONS -g -n PyQt5.sip) # Always release the GIL before calling C++ methods. -n PyQt5.sip is required to not get the PyCapsule error
include_directories(src/ ${SIP_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS} ${CLIPPER_INCLUDE_DIRS} ${NLopt_INCLUDE_DIRS} ${LIBNEST2D_INCLUDE_DIRS})
add_sip_python_module(pynest2d src/Pynest2D.sip ${CLIPPER_LIBRARIES} ${NLopt_LIBRARIES})
find_package(Threads)
find_package(clipper)
find_package(NLopt)
target_link_libraries(pynest2d INTERFACE libnest2d::libnest2d Python::Python Threads::Threads clipper::clipper NLopt::nlopt)

add_sip_module(pynest2d)
install_sip_module(pynest2d)
13 changes: 13 additions & 0 deletions cmake/CMakeBuilder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from sipbuild import SetuptoolsBuilder


class CMakeBuilder(SetuptoolsBuilder):
def __init__(self, project, **kwargs):
print("Using the CMake builder")
super().__init__(project, **kwargs)

def build(self):
""" Only Generate the source files """
print("Generating the source files")
self._generate_bindings()
self._generate_scripts()
15 changes: 13 additions & 2 deletions cmake/FindNLopt.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ else()
endif()

find_path(NLopt_INCLUDE_DIRS nlopt.hpp
${NLopt_PACKAGE_FOLDER}/include
$ENV{NLopt_PATH}
$ENV{NLopt_PATH}/cpp/
$ENV{NLopt_PATH}/include/
Expand All @@ -33,7 +34,8 @@ find_path(NLopt_INCLUDE_DIRS nlopt.hpp
/usr/include/nlopt/
)

set(LIB_SEARCHDIRS
set(LIB_SEARCHDIRS
${NLopt_PACKAGE_FOLDER}/lib
$ENV{NLopt_PATH}
$ENV{NLopt_PATH}/cpp/
$ENV{NLopt_PATH}/cpp/build/
Expand Down Expand Up @@ -69,7 +71,16 @@ find_package_handle_standard_args(NLopt
mark_as_advanced(NLopt_INCLUDE_DIRS NLopt_LIBRARIES)

if(NLopt_FOUND)
add_library(NLopt::nlopt UNKNOWN IMPORTED)
add_library(NLopt::nlopt INTERFACE IMPORTED)
set_property(TARGET NLopt::nlopt
PROPERTY INTERFACE_INCLUDE_DIRECTORIES
${NLopt_INCLUDE_DIRS} APPEND)
if(NLopt_LIBRARIES)
set_property(TARGET NLopt::nlopt
PROPERTY INTERFACE_LINK_LIBRARIES
${NLopt_LIBRARIES} APPEND)
endif()

set_target_properties(NLopt::nlopt PROPERTIES IMPORTED_LOCATION ${NLopt_LIBRARIES})
set_target_properties(NLopt::nlopt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${NLopt_INCLUDE_DIRS})
if(NLopt_LIBRARIES_RELEASE AND NLopt_LIBRARIES_DEBUG)
Expand Down
123 changes: 51 additions & 72 deletions cmake/FindSIP.cmake
Original file line number Diff line number Diff line change
@@ -1,86 +1,65 @@
#Find SIP
#~~~~~~~~
# Find SIP
# ~~~~~~~~
#
#SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
#
#Find the installed version of SIP. FindSIP should be called after Python has
#been found.
# Find the installed version of SIP. FindSIP should be called after Python
# has been found.
#
#This file defines the following variables:
# This file defines the following variables:
#
#SIP_VERSION - SIP version.
#SIP_EXECUTABLE - Path to the SIP executable.
#SIP_INCLUDE_DIRS - The SIP include directories.
# SIP_VERSION - The version of SIP found expressed as a 6 digit hex number
# suitable for comparison as a string.
#
#Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
#Redistribution and use is allowed according to the terms of the BSD license.
#For details see the accompanying COPYING-CMAKE-SCRIPTS file.

if(APPLE)
#Workaround for broken FindPythonLibs. It will always find Python 2.7 libs on OSX.
set(CMAKE_FIND_FRAMEWORK LAST)
endif()

#FIXME: Use the new FindPython3 module rather than these. New in CMake 3.12.
#However currently that breaks on our CI server, since the CI server finds the built-in Python3.6 and then doesn't find the headers.
find_package(PythonInterp 3.5 REQUIRED)
find_package(PythonLibs 3.5 REQUIRED)

#Define variables that are available in FindPython3, so there's no need to branch off in the later part.
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
set(Python3_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
set(Python3_LIBRARIES ${PYTHON_LIBRARIES})

execute_process(
COMMAND ${Python3_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib(plat_specific = False, standard_lib = False))"
RESULT_VARIABLE _process_status
OUTPUT_VARIABLE _process_output
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(${_process_status} EQUAL 0)
string(STRIP ${_process_output} Python3_SITELIB)
else()
message(FATAL_ERROR "Failed to get Python3_SITELIB. Error: ${_process_output}")
endif()
# SIP_VERSION_STR - The version of SIP found as a human readable string.
#
# SIP_BINARY_PATH - Path and filename of the SIP command line executable.
#
# SIP_INCLUDE_DIR - Directory holding the SIP C++ header file.
#
# SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed
# into.

execute_process(
COMMAND ${Python3_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib(plat_specific = True, standard_lib = False))"
RESULT_VARIABLE _process_status
OUTPUT_VARIABLE _process_output
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(${_process_status} EQUAL 0)
string(STRIP ${_process_output} Python3_SITEARCH)
else()
message(FATAL_ERROR "Failed to get Python3_SITEARCH. Error: ${_process_output}")
endif()
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.

get_filename_component(_python_binary_path ${Python3_EXECUTABLE} DIRECTORY)

find_program(SIP_EXECUTABLE sip
HINTS ${CMAKE_PREFIX_PATH}/bin ${CMAKE_INSTALL_PATH}/bin ${_python_binary_path} ${Python3_SITELIB}/PyQt5
)

find_path(SIP_INCLUDE_DIRS sip.h
HINTS ${CMAKE_PREFIX_PATH}/include ${CMAKE_INSTALL_PATH}/include ${Python3_INCLUDE_DIRS} ${Python3_SITELIB}/PyQt5
)
IF(SIP_VERSION)
# Already in cache, be silent
SET(SIP_FOUND TRUE)
ELSE(SIP_VERSION)

execute_process(
COMMAND ${Python3_EXECUTABLE} -c "import sip; print(sip.SIP_VERSION_STR)"
RESULT_VARIABLE _process_status
OUTPUT_VARIABLE _process_output
OUTPUT_STRIP_TRAILING_WHITESPACE
)
FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH} NO_CMAKE_FIND_ROOT_PATH)

if(${_process_status} EQUAL 0)
string(STRIP ${_process_output} SIP_VERSION)
endif()
EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config)
IF(sip_config)
STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION ${sip_config})
STRING(REGEX REPLACE ".*\nsip_version_num:([^\n]+).*$" "\\1" SIP_VERSION_NUM ${sip_config})
STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config})
STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config})
IF(${SIP_VERSION_STR} VERSION_LESS 5)
STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_BINARY_PATH ${sip_config})
STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config})
STRING(REGEX REPLACE ".*\nsip_module_dir:([^\n]+).*$" "\\1" SIP_MODULE_DIR ${sip_config})
ELSE(${SIP_VERSION_STR} VERSION_LESS 5)
FIND_PROGRAM(SIP_BUILD_EXECUTABLE sip-build)
ENDIF(${SIP_VERSION_STR} VERSION_LESS 5)
SET(SIP_FOUND TRUE)
ENDIF(sip_config)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SIP REQUIRED_VARS SIP_EXECUTABLE SIP_INCLUDE_DIRS VERSION_VAR SIP_VERSION)
IF(SIP_FOUND)
IF(NOT SIP_FIND_QUIETLY)
MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}")
ENDIF(NOT SIP_FIND_QUIETLY)
ELSE(SIP_FOUND)
IF(SIP_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find SIP")
ENDIF(SIP_FIND_REQUIRED)
ENDIF(SIP_FOUND)

if(SIP_FOUND)
include(${CMAKE_CURRENT_LIST_DIR}/SIPMacros.cmake)
endif()
ENDIF(SIP_VERSION)

mark_as_advanced(SIP_EXECUTABLE SIP_INCLUDE_DIRS SIP_VERSION)
include(${CMAKE_SOURCE_DIR}/cmake/SIPMacros.cmake)
ADD_DEFINITIONS(-DSIP_VERSION=0x${SIP_VERSION})
57 changes: 57 additions & 0 deletions cmake/FindSIP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Simon Edwards <simon@simonzone.com> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY Simon Edwards <simon@simonzone.com> ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Simon Edwards <simon@simonzone.com> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# FindSIP.py
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.

try:
import sipbuild

print("sip_version:%06.0x" % sipbuild.version.SIP_VERSION)
print("sip_version_num:%d" % sipbuild.version.SIP_VERSION)
print("sip_version_str:%s" % sipbuild.version.SIP_VERSION_STR)

from distutils.sysconfig import get_python_lib
python_modules_dir = get_python_lib(plat_specific=1)
print("default_sip_dir:%s" % python_modules_dir)
except ImportError: # Code for SIP v4
import sipconfig

sipcfg = sipconfig.Configuration()
print("sip_version:%06.0x" % sipcfg.sip_version)
print("sip_version_num:%d" % sipcfg.sip_version)
print("sip_version_str:%s" % sipcfg.sip_version_str)
print("sip_bin:%s" % sipcfg.sip_bin)
print("default_sip_dir:%s" % sipcfg.default_sip_dir)
print("sip_inc_dir:%s" % sipcfg.sip_inc_dir)
# SIP 4.19.10+ has new sipcfg.sip_module_dir
if hasattr(sipcfg, "sip_module_dir"):
print("sip_module_dir:%s" % sipcfg.sip_module_dir)
else:
print("sip_module_dir:%s" % sipcfg.sip_mod_dir)
24 changes: 12 additions & 12 deletions cmake/FindClipper.cmake → cmake/Findclipper.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ else()
endif()

find_path(CLIPPER_INCLUDE_DIRS clipper.hpp
${clipper_PACKAGE_FOLDER}/include
$ENV{CLIPPER_PATH}
$ENV{CLIPPER_PATH}/cpp/
$ENV{CLIPPER_PATH}/include/
Expand All @@ -36,7 +37,8 @@ find_path(CLIPPER_INCLUDE_DIRS clipper.hpp
/usr/include/polyclipping/
)

set(LIB_SEARCHDIRS
set(LIB_SEARCHDIRS
${clipper_PACKAGE_FOLDER}/lib
$ENV{CLIPPER_PATH}
$ENV{CLIPPER_PATH}/cpp/
$ENV{CLIPPER_PATH}/cpp/build/
Expand Down Expand Up @@ -65,7 +67,7 @@ else()
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Clipper
find_package_handle_standard_args(clipper
"Clipper library cannot be found. Consider set CLIPPER_PATH environment variable"
CLIPPER_INCLUDE_DIRS
CLIPPER_LIBRARIES
Expand All @@ -74,15 +76,13 @@ find_package_handle_standard_args(Clipper
mark_as_advanced(CLIPPER_INCLUDE_DIRS CLIPPER_LIBRARIES)

if(CLIPPER_FOUND)
add_library(Clipper::Clipper UNKNOWN IMPORTED)
set_target_properties(Clipper::Clipper PROPERTIES IMPORTED_LOCATION ${CLIPPER_LIBRARIES})
set_target_properties(Clipper::Clipper PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CLIPPER_INCLUDE_DIRS})
if(CLIPPER_LIBRARIES_RELEASE AND CLIPPER_LIBRARIES_DEBUG)
set_target_properties(Clipper::Clipper PROPERTIES
IMPORTED_LOCATION_DEBUG ${CLIPPER_LIBRARIES_DEBUG}
IMPORTED_LOCATION_RELWITHDEBINFO ${CLIPPER_LIBRARIES_RELEASE}
IMPORTED_LOCATION_RELEASE ${CLIPPER_LIBRARIES_RELEASE}
IMPORTED_LOCATION_MINSIZEREL ${CLIPPER_LIBRARIES_RELEASE}
)
add_library(clipper::clipper INTERFACE IMPORTED)
if(CLIPPER_LIBRARIES)
set_property(TARGET clipper::clipper
PROPERTY INTERFACE_LINK_LIBRARIES
${CLIPPER_LIBRARIES} APPEND)
endif()
set_property(TARGET clipper::clipper
PROPERTY INTERFACE_INCLUDE_DIRECTORIES
${CLIPPER_INCLUDE_DIRS} APPEND)
endif()
Loading

0 comments on commit 207c521

Please sign in to comment.