Skip to content

Instantly share code, notes, and snippets.

@Morwenn
Last active August 26, 2022 15:31
Show Gist options
  • Save Morwenn/477221e294d6b9796075f038387e1f18 to your computer and use it in GitHub Desktop.
Save Morwenn/477221e294d6b9796075f038387e1f18 to your computer and use it in GitHub Desktop.
Basic modular Conan recipe to build PCL
cmake_minimum_required(VERSION 2.8.11)
project(cmake_wrapper)
include(conanbuildinfo.cmake)
conan_basic_setup()
if (CONAN_COMPILE_DEFINITIONS_FLANN MATCHES "FLANN_STATIC")
set(FLANN_USE_STATIC ON)
endif()
add_subdirectory(source_subfolder)
# -*- coding: utf-8 -*-
import os
from conans import ConanFile, CMake, tools
from conans.errors import ConanInvalidConfiguration
class LibPclConan(ConanFile):
name = "pcl"
version = "1.11.0-dev" # TODO: change later
description = "The Point Cloud Library is a standalone, large scale, open project for 2D/3D image and point cloud processing"
url = "https://github.com/PointCloudLibrary/pcl"
homepage = "http://www.pointclouds.org/"
license = "BSD-3-Clause"
exports = "CMakeLists.txt"
generators = "cmake"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
# Options for modules
"module_2d": [True, False],
"module_cuda": [True, False],
"module_features": [True, False],
"module_filters": [True, False],
"module_geometry": [True, False],
"module_gpu": [True, False],
"module_io": [True, False],
"module_kdtree": [True, False],
"module_keypoints": [True, False],
"module_ml": [True, False],
"module_octree": [True, False],
"module_outofcore": [True, False],
"module_people": [True, False],
"module_recognition": [True, False],
"module_registration": [True, False],
"module_sample_consensus": [True, False],
"module_search": [True, False],
"module_segmentation": [True, False],
"module_simulation": [True, False],
"module_stereo": [True, False],
"module_surface": [True, False],
"module_surface_on_nurbs": [True, False],
"module_tracking": [True, False],
"module_visualization": [True, False],
# Options for dependencies
"with_cuda": [True, False],
"with_davidsdk": [True, False],
"with_dssdk": [True, False],
"with_ensenso": [True, False],
"with_libpng": [True, False],
"with_libusb": [True, False],
"with_opengl": [True, False],
"with_openni": [True, False],
"with_openni2": [True, False],
"with_pcap": [True, False],
"with_qhull": [True, False],
"with_qt": [True, False],
"with_rssdk": [True, False],
"with_rssdk2": [True, False],
"with_vtk": [True, False]
}
default_options = {
"shared": True,
"fPIC": True,
# TODO: choose which modules are enabled by default
"module_2d": True,
"module_cuda": True,
"module_features": True,
"module_filters": True,
"module_geometry": True,
"module_gpu": True,
"module_io": True,
"module_kdtree": True,
"module_keypoints": True,
"module_ml": True,
"module_octree": True,
"module_outofcore": False,
"module_people": False,
"module_recognition": True,
"module_registration": True,
"module_sample_consensus": True,
"module_search": True,
"module_segmentation": True,
"module_simulation": False,
"module_stereo": True,
"module_surface": True,
"module_surface_on_nurbs": True,
"module_tracking": True,
"module_visualization": False,
# TODO: choose which options are enabled by default
"with_cuda": False,
"with_davidsdk": False,
"with_dssdk": False,
"with_ensenso": False,
"with_libpng": True,
"with_libusb": True,
"with_opengl": True,
"with_openni": False,
"with_openni2": False,
"with_pcap": False,
"with_qhull": False,
"with_qt": False,
"with_rssdk": False,
"with_rssdk2": False,
"with_vtk": False
}
_source_subfolder = "source_subfolder"
_build_subfolder = "build_subfolder"
_cmake = None
scm = {
"type": "git",
"subfolder": _source_subfolder,
"url": "https://github.com/PointCloudLibrary/pcl.git",
"revision": "master" # TODO: change later
}
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def configure(self):
if self.options.with_cuda:
raise ConanInvalidConfiguration("Option 'with_cuda' is not supported yet")
if self.options.with_davidsdk:
raise ConanInvalidConfiguration("Option 'with_davidsdk' is not supported yet")
if self.options.with_dssdk:
raise ConanInvalidConfiguration("Option 'with_dssdk' is not supported yet")
if self.options.with_ensenso:
raise ConanInvalidConfiguration("Option 'with_ensenso' is not supported yet")
if self.options.with_openni:
raise ConanInvalidConfiguration("Option 'with_openni' is not supported yet")
if self.options.with_openni2:
raise ConanInvalidConfiguration("Option 'with_openni2' is not supported yet")
if self.options.with_pcap:
raise ConanInvalidConfiguration("Option 'with_pcap' is not supported yet")
if self.options.with_qhull:
raise ConanInvalidConfiguration("Option 'with_qhull' is not supported yet")
if self.options.with_qt:
raise ConanInvalidConfiguration("Option 'with_qt' is not supported yet")
if self.options.with_rssdk:
raise ConanInvalidConfiguration("Option 'with_rssdk' is not supported yet")
if self.options.with_rssdk2:
raise ConanInvalidConfiguration("Option 'with_rssdk2' is not supported yet")
if self.options.with_vtk:
raise ConanInvalidConfiguration("Option 'with_vtk' is not supported yet")
if self.options.module_outofcore:
raise ConanInvalidConfiguration("Module 'outofcore' is not supported yet")
if self.options.module_people:
raise ConanInvalidConfiguration("Module 'people' is not supported yet")
if self.options.module_simulation:
raise ConanInvalidConfiguration("Module 'simulation' is not supported yet")
if self.options.module_visualization:
raise ConanInvalidConfiguration("Module 'visualization' is not supported yet")
def source(self):
# Make sure PCL can find Conan's Boost no matter the version
tools.replace_in_file(
os.path.join(self._source_subfolder, "PCLConfig.cmake.in"),
"find_package(Boost ",
"find_package(Boost) #"
)
def requirements(self):
# Mandatory requirements
self.requires("boost/1.72.0")
self.requires("eigen/3.3.7")
self.requires("flann/1.9.1")
# Optional requirements
if self.options.with_libpng:
self.requires("libpng/1.6.37")
if self.options.with_libusb:
self.requires("libusb/1.0.23")
# Module-dependent requirements
if self.options.module_simulation:
self.requires("glew/2.1.0@bincrafters/stable")
def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
# Adjust linking options
self._cmake.definitions["PCL_SHARED_LIBS"] = self.options.shared
self._cmake.definitions["PCL_BUILD_WITH_BOOST_DYNAMIC_LINKING_WIN32"] = self.options["boost"].shared
self._cmake.definitions["PCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32"] = self.options["flann"].shared
if self.options.with_qhull:
self._cmake.definitions["PCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32"] = self.options["qhull"].shared
# Do not build extra tooling & options
self._cmake.definitions["BUILD_all_in_one_installer"] = False
self._cmake.definitions["BUILD_apps"] = False
self._cmake.definitions["BUILD_examples"] = False
self._cmake.definitions["BUILD_global_tests"] = False
self._cmake.definitions["BUILD_tools"] = False
self._cmake.definitions["WITH_DOCS"] = False
# Build modules as needed
self._cmake.definitions["BUILD_2d"] = self.options.module_2d
self._cmake.definitions["BUILD_common"] = True # Always build at least common
self._cmake.definitions["BUILD_CUDA"] = self.options.module_cuda
self._cmake.definitions["BUILD_features"] = self.options.module_features
self._cmake.definitions["BUILD_filters"] = self.options.module_filters
self._cmake.definitions["BUILD_geometry"] = self.options.module_geometry
self._cmake.definitions["BUILD_GPU"] = self.options.module_gpu
self._cmake.definitions["BUILD_io"] = self.options.module_io
self._cmake.definitions["BUILD_kdtree"] = self.options.module_kdtree
self._cmake.definitions["BUILD_keypoints"] = self.options.module_keypoints
self._cmake.definitions["BUILD_ml"] = self.options.module_ml
self._cmake.definitions["BUILD_octree"] = self.options.module_octree
self._cmake.definitions["BUILD_outofcore"] = self.options.module_outofcore
self._cmake.definitions["BUILD_people"] = self.options.module_people
self._cmake.definitions["BUILD_recognition"] = self.options.module_recognition
self._cmake.definitions["BUILD_registration"] = self.options.module_registration
self._cmake.definitions["BUILD_sample_consensus"] = self.options.module_sample_consensus
self._cmake.definitions["BUILD_search"] = self.options.module_search
self._cmake.definitions["BUILD_segmentation"] = self.options.module_segmentation
self._cmake.definitions["BUILD_simulation"] = self.options.module_simulation
self._cmake.definitions["BUILD_stereo"] = self.options.module_stereo
self._cmake.definitions["BUILD_surface"] = self.options.module_surface
self._cmake.definitions["BUILD_surface_on_nurbs"] = self.options.module_surface_on_nurbs
self._cmake.definitions["BUILD_tracking"] = self.options.module_tracking
self._cmake.definitions["BUILD_visualization"] = self.options.module_visualization
# Configure dependencies as needed
self._cmake.definitions["WITH_CUDA"] = self.options.with_cuda
self._cmake.definitions["WITH_DAVIDSDK"] = self.options.with_davidsdk
self._cmake.definitions["WITH_DSSDK"] = self.options.with_dssdk
self._cmake.definitions["WITH_ENSENSO"] = self.options.with_ensenso
self._cmake.definitions["WITH_LIBUSB"] = self.options.with_libusb
self._cmake.definitions["WITH_OPENGL"] = self.options.with_opengl
self._cmake.definitions["WITH_OPENNI"] = self.options.with_openni
self._cmake.definitions["WITH_OPENNI2"] = self.options.with_openni2
self._cmake.definitions["WITH_PCAP"] = self.options.with_pcap
self._cmake.definitions["WITH_PNG"] = self.options.with_libpng
self._cmake.definitions["WITH_QHULL"] = self.options.with_qhull
self._cmake.definitions["WITH_QT"] = self.options.with_qt
self._cmake.definitions["WITH_RSSDK"] = self.options.with_rssdk
self._cmake.definitions["WITH_RSSDK2"] = self.options.with_rssdk2
self._cmake.definitions["WITH_VTK"] = self.options.with_vtk
self._cmake.configure(build_folder=self._build_subfolder)
return self._cmake
def build(self):
cmake = self._configure_cmake()
cmake.build()
def package(self):
cmake = self._configure_cmake()
cmake.install()
cmake.patch_config_paths()
self.copy("LICENSE.txt", src=self._source_subfolder, dst="licenses")
def package_info(self):
self.cpp_info.names["cmake_find_package"] = "PCL"
self.cpp_info.names["cmake_find_package_multi"] = "PCL"
self.cpp_info.libs = tools.collect_libs(self)
version_short = ".".join(self.version.split(".")[:2])
self.cpp_info.includedirs = [
"include/pcl-{}".format(version_short)
]
@shelper
Copy link

shelper commented May 16, 2020

I am using your recipe to build PCL with Conan and i got an error:

-- Checking for module 'eigen3'
--   No package 'eigen3' found
-- Found Eigen: /home/username/.conan/data/eigen/3.3.7/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/eigen3 (Required is at least version "3.1") 
-- Eigen found (include: /home/username/.conan/data/eigen/3.3.7/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/eigen3, version: 3.3.7)
-- Checking for module 'flann>=1.7.0'
--   No package 'flann' found
CMake Error at /usr/share/cmake-3.10/Modules/FindPackageHandleStandardArgs.cmake:137 (message):
  Could NOT find FLANN (missing: FLANN_LIBRARY) (Required is at least version
  "1.7.0")
Call Stack (most recent call first):
  /usr/share/cmake-3.10/Modules/FindPackageHandleStandardArgs.cmake:378 (_FPHSA_FAILURE_MESSAGE)
  source_subfolder/cmake/Modules/FindFLANN.cmake:123 (find_package_handle_standard_args)
  source_subfolder/CMakeLists.txt:300 (find_package)

I tried to figure out but could not... have you met this issue?
i am using ubuntu 18.04, and conan 1.25. but i dont think that matters. Flann is installed and built as shown in the attached image
foo

@Morwenn
Copy link
Author

Morwenn commented May 16, 2020

@shelper thanks for the report, I added a line to the CMakeLists.txt that should fix the FLANN detection.

@shelper
Copy link

shelper commented May 16, 2020

@Morwenn i think i figured out the issue, it is because pcl looks for dynamically linked FLann, and what i have is statically linked flann.
after i do : conan install pcl/1.11.0 --build=missing -o pcl:shared=False , everything works...

the question i have is , i have to specify the pcl:shared=False in the command i input,
if i change the default_options in conanfiles.py to : shared=False, it still looks for dynamically linked Flann, do you know why is that?

@Morwenn
Copy link
Author

Morwenn commented May 16, 2020

Oh, good catch. Ideally we would modify the Flann recipe on Conan Center Index to properly export FLANN_USE_STATIC . I think that it possible to export that flag by checking that CONAN_COMPILE_DEFINITIONS_FLANN contains "FLANN_STATIC" in the CMakeLists.txt, let me try that.

@shelper Not the most elegant solution I could think of but that should work now.

@shelper
Copy link

shelper commented May 16, 2020

@Morwenn
any suggestion on the default_options?

Just to answer my own question, i need to run conan export ..... again to get the default option updated in the cmake files of PCL

@Morwenn
Copy link
Author

Morwenn commented May 16, 2020

@shelper Sorry I forgot to address that: pcl:shared should only control whether PCL is compiled as a static or a shared library, you would need to change flann:shared to change whether Flann is compiled and linked as a static or a shared library, it's not transitive and libraries default to static in Conan (just a convention). Otherwise yes, you indeed need to reexport the recipe once you've changed the default option :)

@shelper
Copy link

shelper commented May 16, 2020

thanks for the answer, just let you know that i was able to compile PCL on linux using your recipe without flann:shared but only setting the default_option to shared in conanfile.py....
if Conan defaults to static. then it is PCL's libflann.cmake 's issue, that can only use dynamic lib.
anyway, it is good to know (and a backup if anything is wrong)

@Morwenn
Copy link
Author

Morwenn commented May 16, 2020

I tried the recipe in both shared and static mode with the following addition to the CMakeLists.txt and both worked pretty fine though, managing to locate either the static :

if (CONAN_COMPILE_DEFINITIONS_FLANN MATCHES "FLANN_STATIC")
    set(FLANN_USE_STATIC ON)
endif()

Without that bit PCL's FindFLANN.cmake doesn't know about FLANN_USE_STATIC and takes the else() branch everywhere it appears in a condition, hence why it originally only worked with a shared Flann, but that bit should make the whole thing work no matter whether Flann is static or shared.

@shelper
Copy link

shelper commented Jun 21, 2020

I still have a question here. I am using this recipe to cross build PCL for different platform, based on https://github.com/PointCloudLibrary/pcl/blob/b0d4f4a375218a725165f194ba586bfcb1917a20/cmake/pcl_utils.cmake#L93
the include dir is different for different platform. On LInux, the header go to : ".conan/data/pcl/ver/usr/channel/package/package_id/include/pcl-ver#/pcl/*.h"
but for android the headers go to :
".conan/data/pcl/ver/usr/channel/package/package_id/include/pcl/*.h" without the pcl-ver#,
This causes a problem for conan, as when run conan install .. for projects that requires PCL, conan still looks for header directory in pcl-ver#, which is missing and thus returns empty string for conan variable CONAN_INCLUDE_DIRS_PCL.

I tried a different recipe for PCL at https://github.com/shelper/conan-pcl/tree/gitlab and that one works fine, no pcl-ver# for android, but when run conan install .., conan is able to find the header and put the right path in CONAN_INCLUDE_DIRS_PCL.

Do you know why is that?

Many Thanks !

@Morwenn
Copy link
Author

Morwenn commented Jun 22, 2020

@shelper I haven't tried to build PCL for Android because it's not really among the targets I can test, but other folks apparently got it to work: https://github.com/bashbug/pcl-for-android

As far as I can tell their recipe properly configures the Android toolchain, but most of their configuration is a bit manual instead of using Conan generators. That said it is probably a better place to start to build PCL for Android with Conan.

@shelper
Copy link

shelper commented Jun 22, 2020

Thanks for your reply, i actually made it work with some changes. just FYI info, i uploaded my version here at https://github.com/shelper/conan-pcl/tree/gist

@Morwenn
Copy link
Author

Morwenn commented Jun 22, 2020

@shelper Good to know that things are working now. Do you mind if I integrate your changes to the current recipe and to the similar-but-different recipe I've got on Git proper? I would rather have complete enough versions so that people don't have to pick bits here and there as you've had to do to get a working recipe :)

@shelper
Copy link

shelper commented Jun 22, 2020

feel free to do that.
thanks for your comments, the lines you commented there i would still want to keep, as maybe later i need them for android, for now set them false is good enough

@ahamez
Copy link

ahamez commented Aug 26, 2022

If you can't compile with more recent versions of Boost, try to put "boost:filesystem_version" : 3 in default_options.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment