Showing posts with label CMake. Show all posts
Showing posts with label CMake. Show all posts

Monday, March 15, 2021

Creating a simple CUDA with CMake C++ project

Assuming you have downloaded and installed the right version of the NVIDIA CUDA Toolkit for your NVIDIA GPU card, the next step is to create your awesome C++ CUDA project. In this post, I will illustrate how to create a simple Hello World project using CMake on Ubuntu. 

  1. In a folder, create a CUDA C++ file, e.g. hello.cu. Type in the following code as shown in the snippet below.

    Note: the main function simply calls an empty CUDA mykernel consisting of 1 block and 1 thread per block function. Then it prints out a hello message.

  2. Next, create a CMakeLists.txt file. Type in the following code as shown.

    Note: The CMakeLists.txt simply tells CMake to use C++ and CUDA languages and then defines the executable and its source.


  3. Create a build directory. Then change directory into the build directory and run the cmake command.

    $ mkdir build
    $ cd build
    $ cmake ..


    The processing messages appear.


  4. Now compile the project with the make command.

    $ make




  5. Finally, run the hello executable.

    $ ./hello

    The message "Hello CUDA!" is printed to the screen.

The sample project can be downloaded from the Github repository at https://gitlab.com/dominoc925/hello-cuda-cmake

Monday, September 30, 2019

CMake example for cross compiling and using a static library for a Raspberry Pi on an Ubuntu PC

Compiling source code on a Raspberry Pi can be sluggish compared to a PC. So instead I decided that cross compilation on an Ubuntu PC would be faster and therefore more productive of my time. So after a few false starts, I finally managed to get the workflow working. This post shows a simple example of how to compile a C++ static library and using that in an executable for Raspberry Pi using the CMake build system on an Ubuntu PC.

Down the Raspberry Pi build tools
The first thing is to get the Raspberry cross compilation tools from the git repository.

In Ubuntu, open a Terminal. Type in the following to download the tools to a folder e.g. /path/to/programs/pi/.

$ cd ~/programs/pi/
$ git clone https://github.com/raspberrypi/tools.git


Create a CMake toolchain file
Next, create a cmake file e.g. /path/to/workspace/toolchain-rpi.cmake specifying the correct Raspberry cross compilation tools for compiling C/C++ source files with the CMAKE_C_COMPILER and CMAKE_CXX_COMPILER macros. Also the root folder of the Raspberry Pi libraries and include files need to be specified with the CMAKE_FIND_ROOT_PATH macro.

Choose the right ones for your Raspberry Pi chipset.

Listing of toolchain-rpi.cmake
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)

# define the C cross compiler for the Raspberry Pi 
SET(CMAKE_C_COMPILER $ENV{HOME}/programs/pi/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)

# define the C++ cross compiler for the Raspberry Pi
SET(CMAKE_CXX_COMPILER $ENV{HOME}/programs/pi/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++)

# define the root location of the Raspberry Pi libraries and includes
SET(CMAKE_FIND_ROOT_PATH $ENV{HOME}/programs/pi/tools/arm-bcm2708/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot)

SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

add_definitions(-Wall -std=c11)

Create the workspace
In the same example project workspace folder /path/to/workspace/, create two folders animallib and uselib, the first for the library files, and the later for the executable files.



Create the static library
The next step is to create the header file and define the classes that will be used by the example executable. Place the Animal.h and Animal.cpp files respectively in the include and src folders under the /path/to/workspace/animallb/ folder.

Listing of Animal.h
#include <string>

using namespace std;

class Animal {
        private:
                string name;
        public:
                Animal(string);
                virtual void print_name();
};

Listing of Animal.cpp
#include <iostream>
#include "Animal.h"

using namespace std;

Animal::Animal(string name): name (name) {}

void Animal::print_name(){
        cout << "Name is " << this->name << endl;
}

Create the static library's CMakeLists.txt file in the animallib folder e.g. /path/to/workspace/animallib/. As defined, this will help to generate a static library libanimallib.a and a header file animallib_Export.h.

cmake_minimum_required(VERSION 2.8.6)
project (animallib)

set (BUILD_SHARED_LIBS OFF)
set (CMAKE_BUILD_TYPE Debug)

#include *.h files under the include folder and
#the project's output folder e.g. build
include_directories (include ${PROJECT_BINARY_DIR})

#compile all *.cpp source files under the src folder
file (GLOB SOURCES "src/*.cpp")

#output static library export file *.a and
#output macro definitions include file
include (GenerateExportHeader)
add_library(animallib STATIC ${SOURCES})
GENERATE_EXPORT_HEADER (animallib
        BASE_NAME animallib
        EXPORT_MACRO_NAME animallib_EXPORT
        EXPORT_FILE_NAME animallib_Export.h
        STATIC_DEFINE animallib_BUILT_AS_STATIC
        )

Open up a Terminal and change directory to the static library's folder e.g. /path/to/workspace/animallib/.

If the build folder does not exist, create it.

$ mkdir build
$ cd build

Type in the cmake command with the CMAKE_TOOLCHAIN_FILE variable pointing to the previously created Raspberry Pi toolchain CMake file.

$ cmake -D CMAKE_TOOLCHAIN_FILE=/path/to/workspace/toolchain-rpi.cmake ..

Build files are generated


In the Terminal, type in the make command to generate the static library file.
$ make
Static library compilation messages
Using the static library in a separate C++ application
Now that the library has been generated, the next thing is to use the library's classes and functions in an executable e.g. uselib project under /path/to/workspace/uselib/.

Listing of uselib.cpp
#include "Animal.h"

#include "animallib_Export.h"

int main(int argc, char *argv[]){
        Animal animal("Dog");
        animal.print_name();
        return (0);
}

Place the source code file uselib.cpp under the src directory e.g. /path/to/workspace/uselib/src/.

Then create a CMakeLists.txt file under the /path/to/workspace/uselib/ folder.
cmake_minimum_required(VERSION 2.8.6)
project (UseLib)

# link as a static library
set(CMAKE_EXE_LINKER_FLAGS "-static")

set (EXAMPLE_DIR $ENV{HOME}/Documents/workspace/learn_rpi/)

# name and location of the library to link with the executable
set (PROJECT_LINK_LIBS animallib)
link_directories (${EXAMPLE_DIR}/animallib/build/)

include_directories (
        ${EXAMPLE_DIR}/animallib/include
        ${EXAMPLE_DIR}/animallib/build
        )

#compile all *.cpp source files under src folder
file (GLOB SOURCES "src/*.cpp")

#output executable name as uselib
add_executable (uselib ${SOURCES})
target_link_libraries (uselib ${PROJECT_LINK_LIBS})

Open up a Terminal. Change directory to the /path/to/workspace/uselib/ folder.

If the build directory does not exist, type in the following to create it.

$ mkdir build

Type in the cmake command with the CMAKE_TOOLCHAIN_FILE variable pointing to the previously created Raspberry Pi toolchain CMake file.

$ cmake -D CMAKE_TOOLCHAIN_FILE=/path/to/workspace/toolchain-rpi.cmake ..

The build files are generated
Compile the executable with the make command.
$ make

Compilation messages
Once the executable uselib has been generated, it can be copied to the Raspberry Pi and run. If you have an arm emulator e.g. qemu installed on the Ubuntu PC, then it can be executed as shown below.
Running the Raspberry Pi executable on the Ubuntu PC with QEMU

Monday, July 29, 2019

ROS: Fix "Unable to get message class for type custom_msgs/gnssSample"

I recently received a ROS bag file recorded with a Velodyne VLP-16 LiDAR sensor and a XSens IMU-GPS sensor. When playing back the bag file, the ROS rqt plugins could not expand the XSens messages. The error message: can not get message class for type "custom_msgs/gnssSample" is shown in the screen shot below.
 
I found a deprecated Github repository for the XSens MTi ROS node at https://github.com/xsens/xsens_mti_ros_node that has the definitions for the custom message gnssSample. However, the repository's package name is xsens_msgs while the bag file's package name is custom_msgs. I had to rename the package to get ROS to recognize the bag file's messages. So the following steps were how I resolved the problem.
  1. Follow the tutorial at https://wiki.ros.org/ROS/Tutorials/CreatingPackage to create a Catkin workspace e.g. /home/yourname/catkin_ws/.
  2. Open up a Terminal and change the directory to /home/yourname/catkin_ws/src/.

    $ cd /home/yourname/catkin_ws/src
  3. Download the XSens MTi ROS Node repository.

    $ git clone https://github.com/xsens/xsens_mti_ros_node
  4. Using a text editor, open up the file /home/yourname/catkin_ws/src/xsens_mti_ros_node/src/xsens_msgs/package.xml.


  5. Change the package name to custom_msgs as shown below.


  6. Open up the file /home/yourname/catkin_ws/src/xsens_mti_ros_node/src/xsens_msgs/CMakeLists.txt.



  7. Change the project name to custom_msgs as shown below.


  8. Now in a Terminal change to the catkin root directory.

    $ cd /home/yourname/catkin_ws
  9. Compile the package by entering the command:

    $ catkin_make
If the compilation is successful, now when reviewing the messages with rqt, the custom_msgs/gnssSample message can be expanded, as shown below.

Monday, October 29, 2018

Setup CMakeLists.txt for Android Studio and OpenCV C++ coding

If you want to develop C++ code making use of Android and OpenCV classes, then you have to configure Android Studio's CMakeLists.txt build file accordingly.

Please follow the previous post https://dominoc925.blogspot.com/2018/10/how-i-setup-opencv4android-java-sdk.html to download and setup the OpenCV4Android Java SDK with and Android project before doing the following steps.
  1. In Android Studio, open up the app's build.gradle file.

    Note: the OpenCV native libraries are under the jniLibs directory relative to the app's build.gradle file according to the source set jniLibs srcDirs parameter.
     

  2. Enter the cmake cpp flags and platform abi filters  in the android defaultConfig externalNativeBuild section, as shown below.

    externalNativeBuild {
        cmake {
          cppFlags "-frtti -fexceptions"        
    
    abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
    }
    }

  3. Next, open up the CMakeLists.txt file in the editor.

     
  4. Add in the cmake macros to add in the path to the OpenCV C++ include files e.g. /path/to/OpenCV-android-sdk/sdk/native/jni/include/

     
  5.  Then, use the macro add_library to add the OpenCV library.

  6. Next, use the macro set_target_properties to tell CMake the location of the OpenCV library.

    set_target_properties(
         lib_opencv        
    
    PROPERTIES
    IMPORTED_LOCATION
    ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/${ANDROID_ABI}/libopencv_java3.so
    )


  7. Finally, link the OpenCV library with your code with the target_link_libraries macro.

The full sample of the CMakeLists.txt file is shown below.

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

set (OPENCV4ANDSDK_INCLUDE
        /path/to/OpenCV-android-sdk/sdk/native/jni/include)
include_directories(
    ${OPENCV4ANDSDK_INCLUDE}
)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        src/main/cpp/native-lib.cpp)
add_library(
        lib_opencv
        SHARED
        IMPORTED
)
set_target_properties(
        lib_opencv
        PROPERTIES
        IMPORTED_LOCATION
        ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/${ANDROID_ABI}/libopencv_java3.so
)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)


# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}
        lib_opencv
        )




Monday, October 22, 2018

How I setup OpenCV4Android Java SDK with a blank Android project

Setting up an Android Studio project with OpenCV3 can be a little tricky. The official documentation is still using Eclipse and has not been updated with Android Studio. So setting up OpenCV with Android Studio required some trial and error experimentation. I managed to get a template Android Studio project to load the native OpenCV library with the following steps.

Download OpenCV4AndroidSdk
  1. If you have not done so, download OpenCV4Android from this website https://sourceforge.net/projects/opencvlibrary/files/opencv-android/
  2. Extract the files into a folder e.g. /path/to/Open-CV-android-sdk/
Create an Android Project with C++ Support
  1.  Run Android Studio. Choose Create a New Project.

  2. In the Create New Project dialog box, toggle on Include C++ support.
  3. Choose appropriate options and click Next in the following screens.
  4. Click Finish.

    The new project is created.
Import the OpenCV module into Gradle
  1. In the Android Studio File menu, select File | New | Import Module.

    The Import Module from Source dialog box appears.
  2. In the Source directory field, click the ... button and browse to the downloaded OpenCV4Android files and select the java folder e.g. /path/to/OpenCV-android-sdk/sdk/java/.
  3. Optional. In the Module name field, type in a name e.g. :opencv.
  4. Click Next and Finish.

    The module is imported (with most likely error messages)
  5. Options. You can download the missing dependencies by clicking the Install missing platforms and sync project link. Or you can edit the OpenCV4Android's build.gradle file to enter the installed dependencies.
Fix OpenCV4Android configuration files
  1. In Android Studio, open up the file build.gradle from the imported module opencv module e.g. /path/to/opencv/build.gradle. It may be necessary to change the Project pane to display as project view.

  2. In the editor, changed the compiledSdkVersion to 27 (or any installed version), the targetSdkVersion to 27 (or any installed version).
  3. Then sync the gradle project.

    The project is synced but now there is an error about the manifest file.
  4. Open up the manifest file /path/to/opencv/src/main/AndroidManifest.xml in the editor.

  5. Now, comment out the uses-sdk line as shown in the screenshot above.
  6. Sync the project again.

    The OpenCV module is successfully configured.
Add the OpenCV module as a dependency to the Android App project
  1. In Android Studio, select App in the Project pane.
  2. Select File | Project Structure.

    The Project Structure dialog box appears.
  3. Select app. Then click the Dependencies tab. Click +. Choose module dependency.
  4. Choose the imported Opencv module.

    OpenCV is appended to the list.
  5. Click OK.

    The module is added the Android App project.
Copy over the OpenCV native platform binaries to the Android App project
  1.  Open up a File Explorer. Select all the native platform folders under the /path/to/OpenCV-android-sdk/sdk/native/libs/*.

  2. Right click and select Copy.
  3. In Android Studio, right click on the app folder (in project view). Choose Paste.

    The Copy dialog box appears.
  4. In the To directory field, change the text to /path/to/myandroid/app/jniLibs/.
  5. Click OK.

    The native binaries are copied to the project.
  6. To enable the Android project to know where the native binaries are, open up the app's build.gradle file in the editor.

  7. Add in the android class, add in the following sourceSets lines:

    Note: 'jniLibs' means the jniLibs directory relative to this build.gradle file location.
    sourceSets {
        main {
            jniLibs.srcDirs = ['jniLibs']
        }
    }
  8. Sync the project.
Load the native library
  1.  In the MainActivity Kotlin class, type in the following to load in the OpenCV library.

    System.loadLibrary("opencv_java3")
  2. If everything is configured properly, then the Android app can be launched successfully.

    Now you can make any java/Kotlin calls to the built in OpenCV interfaces.

Monday, October 8, 2018

Nana CMake file for Ubuntu

Nana is a "cross-platform library for GUI programming in modern C++ style". More information is available on this website http://nanapro.org/en-us/.

I wanted to use this library with a simple C++ application on Ubuntu. So I created a CMake project with the following folders (see the screenshot below).

Following the getting started and installation instructions here http://nanapro.org/en-us/blog/2016/05/an-introduction-to-nana-c-library/, I downloaded the nana source files, placed them under the nana folder and compiled them into the static library libnana.a.

Next, I created a simple Hello World C++ source file and placed under the src folder.

I then created a CMakeLists.txt file that describes the project and dependencies.

cmake_minimum_required(VERSION 2.8.6)
project(runnana)

find_package (Threads REQUIRED)
find_package (X11 REQUIRED)
find_package(Freetype REQUIRED)

set (CMAKE_BUILD_TYPE Debug)
set (LIBRARY_OUTPUT_PATH bin)

set (CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_STANDARD_REQUIRED ON)

set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ./bin)
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ./bin)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin)

set (NANA_INCLUDE nana/include)
set (NANA_LINK nana/build/bin)

include_directories (
 ${FREETYPE_INCLUDE_DIRS}
 ${X11_INCLUDE_DIR}
 ${NANA_INCLUDE}
)
link_directories (
 ${NANA_LINK}
)
set (RUNNANA_LINK_LIBS
 stdc++fs
 nana
 ${X11_LIBRARIES}
 ${CMAKE_THREAD_LIBS_INIT}
 rt
 Xft
 png
 asound
 fontconfig
 ${FREETYPE_LIBRARIES}
)
set (RUNNANA_INCLUDE
 include
)

file (GLOB RUNNANA_SOURCES "src/*.c*")
add_executable (runnana ${RUNNANA_SOURCES})
target_include_directories (runnana PUBLIC ${RUNNANA_INCLUDE})
target_link_libraries (runnana ${RUNNANA_LINK_LIBS} stdc++fs)

Using this CMake file, I can easily build the project and compile the simple hello world executable, as shown below.



The example hello world application.




Monday, September 24, 2018

Use CMake to build Visual Studio C++ projects with PDAL on Windows

The tutorial on the PDAL website https://pdal.io/development/writing.html provides the details on developing and compiling a simple C++ program using the PDAL API on *nux. I followed the steps but encountered errors trying to compile the example on Windows 10. The following screenshot shows the compilation errors - the Microsoft Visual Studio linker could not find some external symbols such as __imp_htonl_ among others.


 
To fix the compilation errors, the Windows library ws2_32.lib needs to be linked to the final executable. This can be done in the following steps:
  1. Add the library ws2_32 to the CMakeLists.txt file, as shown below.

  2. Run CMake to build the Visual Studio project files.

    C:\> cmake -G"Visual Studio 15 2017 Win64" ..


    The project files are generated.

  3. Open up the solution project in Visual Studio. Then build the solution.

    The project is successfully built and the executable is generated.

Monday, September 19, 2016

Create a Windows Installer using CMake and CPack

CMake can be used to create a Windows installer with CPack and NSIS (Nullsoft Scriptable Install System). NSIS can be downloaded from http://nsis.sourceforge.net. This post follows and extends the tutorial from the CMake Wiki at https://cmake.org/Wiki/CMake:Component_Install_With_CPack.

I wanted to build a Windows installer for a 64 bit Visual Studio application that was build-managed using CMake. This post makes use of the example source code downloadable from https://cmake.org/Wiki/File:ComponentExampleStart.zip.

Add in CPACK macros to CMakeLists.txt
  1. Download and extract the example zip file into a folder e.g. D:\Temp\ComponentExampleStart\ as shown below. I then created a build sub-folder build underneath the D:\Temp\ComponentExampleStart\Source\ folder.
  2. Use a text editor and edit the CMakeLists.txt file to add in CPACK macros according to the Wiki. An edited example is shown below.
cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)
project(MyLib)

add_library(mylib mylib.cpp)

add_executable(mylibapp mylibapp.cpp)
target_link_libraries(mylibapp mylib)

install(
  TARGETS mylib 
  ARCHIVE
  DESTINATION lib
  COMPONENT libraries
  )
install(
  TARGETS mylibapp
  RUNTIME
  DESTINATION bin
  COMPONENT applications
  )
install(
  FILES mylib.h
  DESTINATION include
  COMPONENT headers
  )
#
# CPACK macros below here
#
set (CPACK_PACKAGE_NAME "MyLib")
set (CPACK_PACKAGE_VENDOR "CMake.org")
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyLib - CPack Component Installation Example")
set (CPACK_PACKAGE_VERSION "1.0.0")
set (CPACK_PACKAGE_VERSION_MAJOR "1")
set (CPACK_PACKAGE_VERSION_MINOR "0")
set (CPACK_PACKAGE_VERSION_PATCH "0")
set (CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")

# Define components and their display names
set (CPACK_COMPONENTS_ALL applications libraries headers)
set (CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "MyLib Applications")
set (CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
set (CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ Headers")

# Human readable component descriptions
set (CPACK_COMPONENT_APPLICATIONS_DESCRIPTION
  "An extremely useful application that makes use of MyLib")
set (CPACK_COMPONENT_LIBRARIES_DESCRIPTION
  "Static libraries used to build programs with MyLib")
set (CPACK_COMPONENT_HEADERS_DESCRIPTION
  "C/C++ header files for use with MyLib")

# Define dependencies between components
set (CPACK_COMPONENT_HEADERS_DEPENDS libraries)

# Define groups
set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime")
set(CPACK_COMPONENT_LIBRARIES_GROUP "Development")
set(CPACK_COMPONENT_HEADERS_GROUP "Development")

set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION
   "All of the tools you'll ever need to develop software")

# Define NSIS installation types
set(CPACK_ALL_INSTALL_TYPES Full Developer)
set(CPACK_COMPONENT_LIBRARIES_INSTALL_TYPES Developer Full)
set(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full)
set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full)
 
# Must be after the last CPACK macros
include(CPack)

Generate the Visual Studio solution

  1. Open up a Command Prompt. Change to the build directory.

    D:> cd \temp\ComponentExampleStart\Source\build
  2. Use the cmake command to generate the build files.

    D:> cmake -G "Visual Studio 14 2015 Win64" ..

    The build files are generated.
Build the Visual Studio solution and generate the installer
  1. Using Visual Studio, open up the generated solution e.g. MyLib.sln.

  2. Since I wanted a release build, in Visual Studio I changed from Debug to Release, as shown below. Then I selected Build.

    The release binaries are generated.
  3. Next, in the Solution Explorer, select and mouse right click on the PACKAGE project.

    A pop down menu appears.
  4. Choose Build.



    CPack processing message appears.


    The NSIS installer is generated.