DEV Community

Nor
Nor

Posted on

How to compile PCL to android?

Update:

Just use vcpkg.json directly in windows in android studio.
You can get PCL complied into your android project.

Just click the run button.

You may get errors like: thread problem, openmp libomp.a problem.
Fix those in the CMakeLists.txt.

Takes about 2 hours.
(if get curl internet problem, just rerun.)

disclaimer: this answer received help from AI, and is tested to be working in my situation.

pwsh.exe -new_console:a

cd C:
cd C:/
mkdir src
cd C:/src
git clone https://github.com/microsoft/vcpkg.git

cd C:/src/vcpkg
git checkout 2026.03.18
./bootstrap-vcpkg.bat



vcpkg.json compile pcl to android  
// ${vcpkgRoot}/scripts/buildsystems/vcpkg.cmake ${ndkDir}/build/cmake/android.toolchain.cmake
// set(ENV{ANDROID_NDK_HOME} "${CMAKE_ANDROID_NDK}") set(ENV{ANDROID_NDK_HOME} "${ANDROID_NDK}")

Enter fullscreen mode Exit fullscreen mode
app\.cxx
app\build

app\src\main\cpp\CMakeLists.txt
app\src\main\cpp\native-lib.cpp
app\src\main\cpp\vcpkg.json

app\src\main\java\com\example\pcldemo4\MainActivity.kt

app\build.gradle
Enter fullscreen mode Exit fullscreen mode
{
  "name": "pcldemo4",
  "version": "1.0.0",
  "dependencies": [
    "pcl"
  ]
}
Enter fullscreen mode Exit fullscreen mode
cmake_minimum_required(VERSION 3.22.1)

if(CMAKE_ANDROID_NDK)
    set(ENV{ANDROID_NDK_HOME} "${CMAKE_ANDROID_NDK}")
endif()

# satisfy Threads for Boost/PCL
set(CMAKE_THREAD_LIBS_INIT "")
set(Threads_FOUND TRUE)
if(NOT TARGET Threads::Threads)
    add_library(Threads::Threads INTERFACE IMPORTED)
endif()

project("pcldemo4")

find_package(PCL CONFIG REQUIRED)

add_library(${CMAKE_PROJECT_NAME} SHARED native-lib.cpp)

# --- NEW: STATIC OPENMP LINKING ---
# We find the static library (.a) in your specific NDK version
# Note: NDK 27 uses Clang 18. Adjust the '18' if your path differs.
set(NDK_CLANG_LIB_DIR "${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/windows-x86_64/lib/clang/18/lib/linux/aarch64")

# If the path above is wrong, CMake will tell us.
# We link the .a file directly to avoid the .so dependency.
target_link_libraries(${CMAKE_PROJECT_NAME}
        ${PCL_LIBRARIES}
        "${NDK_CLANG_LIB_DIR}/libomp.a"
        log
        atomic)

# Important: Remove the -fopenmp from target_link_options if it was there,
# but keep it in compile options so the compiler understands the pragmas.
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -fopenmp)
Enter fullscreen mode Exit fullscreen mode
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace 'com.example.pcldemo4'
    compileSdk {
        version = release(36)
    }

    //    ndkVersion "25.2.9519653"
    ndkVersion "27.3.13750724"

    defaultConfig {
        applicationId "com.example.pcldemo4"
        minSdk 30
        targetSdk 36
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        ndk {
            abiFilters "arm64-v8a"
        }

        externalNativeBuild {
            cmake {
                abiFilters "arm64-v8a"

                //                def vcpkgRoot = System.getenv("VCPKG_ROOT")
                //                def vcpkgRoot = "C:/src/vcpkg"
                //                def ndkDir = android.ndkDirectory.absolutePath
                //                def ndkDir = "C:/Users/nshln/AppData/Local/Android/Sdk/ndk/27.3.13750724"

                def vcpkgRoot = "C:/src/vcpkg"
                def ndkDir = android.ndkDirectory.absolutePath

                arguments "-DCMAKE_TOOLCHAIN_FILE=${vcpkgRoot}/scripts/buildsystems/vcpkg.cmake",
                        "-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=${ndkDir}/build/cmake/android.toolchain.cmake",
                        "-DVCPKG_TARGET_TRIPLET=arm64-android",
                        // Ensure the NDK's OpenMP is linked statically
                        // so we don't have to worry about missing .so files
                        "-DANDROID_STL=c++_shared"

            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.22.1"
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = '11'
    }
    buildFeatures {
        compose true
    }
}

dependencies {
    implementation libs.androidx.core.ktx
    implementation libs.androidx.lifecycle.runtime.ktx
    implementation libs.androidx.activity.compose
    implementation platform(libs.androidx.compose.bom)
    implementation libs.androidx.compose.ui
    implementation libs.androidx.compose.ui.graphics
    implementation libs.androidx.compose.ui.tooling.preview
    implementation libs.androidx.compose.material3
    implementation libs.androidx.compose.material3.adaptive.navigation.suite
    testImplementation libs.junit
    androidTestImplementation libs.androidx.junit
    androidTestImplementation libs.androidx.espresso.core
    androidTestImplementation platform(libs.androidx.compose.bom)
    androidTestImplementation libs.androidx.compose.ui.test.junit4
    debugImplementation libs.androidx.compose.ui.tooling
    debugImplementation libs.androidx.compose.ui.test.manifest
}
Enter fullscreen mode Exit fullscreen mode
#include <jni.h>
#include <string>
#include <vector>
#include <sstream>

// PCL Headers
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/extract_indices.h>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_pcldemo4_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {

    std::stringstream ss;
    ss << "--- PCL Complex Test ---\n";

    // 1. Create a PointCloud and fill it with a "Noisy Plane"
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    cloud->width  = 500;
    cloud->height = 1;
    cloud->points.resize(cloud->width * cloud->height);

    for (auto& point: cloud->points) {
        point.x = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
        point.y = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
        // We set Z to near 0 with a little noise to simulate a floor
        point.z = 0.05f * (static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
    }
    ss << "Generated " << cloud->size() << " noisy floor points.\n";

    // 2. Estimate Normals (Proves KD-Tree and Eigen are working)
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    ne.setInputCloud(cloud);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    ne.setSearchMethod(tree);
    pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
    ne.setKSearch(10);
    ne.compute(*cloud_normals);
    ss << "Computed " << cloud_normals->size() << " normals using KD-Tree.\n";

    // 3. Segment the Plane using RANSAC (Proves Sample Consensus and Segmentation)
    pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
    pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
    pcl::SACSegmentation<pcl::PointXYZ> seg;
    seg.setOptimizeCoefficients(true);
    seg.setModelType(pcl::SACMODEL_PLANE);
    seg.setMethodType(pcl::SAC_RANSAC);
    seg.setDistanceThreshold(0.01);
    seg.setInputCloud(cloud);
    seg.segment(*inliers, *coefficients);

    if (inliers->indices.empty()) {
        ss << "Result: Could not find a plane.\n";
    } else {
        // Output the plane equation: ax + by + cz + d = 0
        ss << "Result: Found a plane!\n";
        ss << "Inliers count: " << inliers->indices.size() << "\n";
        ss << "Plane Equation: \n"
           << coefficients->values[0] << "x + "
           << coefficients->values[1] << "y + "
           << coefficients->values[2] << "z + "
           << coefficients->values[3] << " = 0\n";
    }

    return env->NewStringUTF(ss.str().c_str());
}
Enter fullscreen mode Exit fullscreen mode


Following is outdated, \
and has lots manual path linking problem after the copy, \
dont use it, you should use method above.


Just a guide, and a confirmation of:
using wsl2 on windows 11 can compile PCL to android, with the help of vcpkg.

export ANDROID_NDK_HOME=~/android-sdk/android-ndk-r25c

cd ~
[ ! -d "vcpkg" ] && git clone https://github.com/microsoft/vcpkg.git

cd ~/vcpkg
git checkout 2026.03.18
./bootstrap-vcpkg.sh

cd ~/vcpkg

# Remove the PCL build cache specifically
rm -rf buildtrees/pcl
rm -rf packages/pcl_arm64-android

# Optional: If you think the dependencies (Boost/Eigen) are also messed up:
rm -rf buildtrees/boost
rm -rf buildtrees/flann

# --recurse: Ensures that if a dependency (like Flann) needs an update due to the new vcpkg version, it gets updated too.
./vcpkg install pcl:arm64-android --recurse


rm -rf /root/vcpkg/buildtrees/pcl
VCPKG_MAX_CONCURRENCY=2 ./vcpkg install pcl:arm64-android --recurse --clean-after-build






fsutil.exe file setCaseSensitiveInfo "D:\usp\uhpsj\proj\pcl_android_wsp" enable

sudo cp -r /root/vcpkg/installed/arm64-android/* /mnt/d/usp/uhpsj/proj/pcl_android_wsp/


cd /root/vcpkg/installed/
sudo zip -r /mnt/d/usp/uhpsj/proj/pcl_android_sdk.zip arm64-android/


cd /root/vcpkg
sudo zip -r /mnt/d/usp/uhpsj/proj/vcpkg_scripts.zip scripts/

Enter fullscreen mode Exit fullscreen mode

The PCL version I got is:

root@Azih:~/vcpkg# ./vcpkg list arm64-android
boost-algorithm:arm64-android                     1.90.0#1            Boost algorithm module
boost-align:arm64-android                         1.90.0#1            Boost align module
boost-any:arm64-android                           1.90.0#1            Boost any module
boost-array:arm64-android                         1.90.0#1            Boost array module
boost-asio:arm64-android                          1.90.0#1            Boost asio module
boost-asio[deadline-timer]:arm64-android                              Build with deadline_timer support
boost-asio[spawn]:arm64-android                                       Build with spawn (stackful coroutines) support
boost-assert:arm64-android                        1.90.0#1            Boost assert module
...
boost-variant2:arm64-android                      1.90.0#1            Boost variant2 module
boost-variant:arm64-android                       1.90.0#1            Boost variant module
boost-winapi:arm64-android                        1.90.0#1            Boost winapi module
boost-xpressive:arm64-android                     1.90.0#1            Boost xpressive module
bzip2:arm64-android                               1.0.8#6             bzip2 is a freely available, patent free, high-q...
bzip2[tool]:arm64-android                                             Builds bzip2 executable
eigen3:arm64-android                              5.0.1               C++ template library for linear algebra: matrice...
flann:arm64-android                               2022-10-28          Fast Library for Approximate Nearest Neighbors
liblzma:arm64-android                             5.8.2#1             Compression library with an API similar to that ...
libpng:arm64-android                              1.6.55              libpng is a library implementing an interface fo...
lz4:arm64-android                                 1.10.0              Lossless compression algorithm, providing compre...
nanoflann:arm64-android                           1.9.0               nanoflann is a C++11 header-only library for bui...
pcl:arm64-android                                 1.15.1#1            Point Cloud Library (PCL) is open source library...
qhull:arm64-android                               8.0.2#6             computes the convex hull, Delaunay triangulation...
zlib:arm64-android                                1.3.1               A compression library
zstd:arm64-android                                1.5.7               Zstandard - Fast real-time compression algorithm
root@Azih:~/vcpkg#
Enter fullscreen mode Exit fullscreen mode

Note:

disclaimer: this answer received help from AI, and is tested to be working in my situation.

DEV.to markdown...

Top comments (0)