Skip to content

Instantly share code, notes, and snippets.

@rohit-kumar-j
Last active August 9, 2024 09:05
Show Gist options
  • Save rohit-kumar-j/c42f244f5f3d49c5fd39e15efc09a4a2 to your computer and use it in GitHub Desktop.
Save rohit-kumar-j/c42f244f5f3d49c5fd39e15efc09a4a2 to your computer and use it in GitHub Desktop.
Basic Setup :: VS Code, Torch C++ with CMakeLists

Setup VS Code, Torch C++ with CMake

Follow these steps to create a basic CMake project with torch C++ enabled. The proposed folders structure is not mandatory, but is focused to run tests with ease.

We will be working with VS-Code, for Visual Studio, find a tutorial ,by Khareed, here

Table Of Contents


Setup VS Code

VS Code Extensions To Make Life Easier

VS Code Extensions to make life easier:

  • C/C++ for Intellisense support
  • CMake for cmake language support
  • clangd for autocomplete, errors and warnings, etc.
  • CMakeTools for automating cmake builds, tests,etc.

Intellisense Support for Torch

To get intellisense support for torch, we will create (and/or) add a path to includePath in the settings.json file:

{
        "configurations": [
                {
                        "name": "Win32",
                        "includePath": [
                                "${workspaceFolder}/**",
                                // Add this line below explicitly (torch.h lives here)
                                "${workspaceFolder}/external/libtorch/include/torch/csrc/api/include",
                                ],
                        // other settings, etc......
                        }
                }

Now we can include <torch/torch.h> in our .cpp and .h files.

Change the current C/C++ Configuration Provider

  • Goto command pallet (Ctrl+Shift+P)
  • Search for C/C++: Change Configuration Provider
  • Select CMake Tools

Make CMake Visible in Activity Bar

Right click on activity bar and make CMake visible if not visible. This will help in exploring the CMake project.


Setting up My_Torch_Project

We can now create an example project called My_Torch_Project which is configured with CMake with the following folder structure.

Project Folder Structure

Note: We will call them by their assigned names (assigned names are in "{ NAME }" ).

  • For example:
    • Project Cmake file refers to --> My_Torch_Project/CMakeLists.txt
    • Test Cmake file refers to --> My_Torch_Project/test/CMakeLists.txt and so on...

In this example, My_Torch_Project/test/test_2/* and My_Torch_Project/src/* files require torch.

My_Torch_Project
|
|-CMakeLists.txt <--------------- {Project} CMakeLists.txt
|
|-external
|        |-libtorch
|        |-another_dependency
|
|-src
|   |-main.cpp
|   |-main.h
|
|-test
|    |-CMakeLists.txt  <--------------- {Test} CMakeLists.txt
|    |    
|    |-test_1
|    |      |-CMakeLists.txt <--------------- {Test_1} CMakeLists.txt
|    |      |-test_1.cpp
|    |      |-test_1.h
|    |
|    |-test_2
|    |      |-CMakeLists.txt <--------------- {Test_2} CMakeLists.txt
|    |      |-test_2.cpp
|    |      |-test_2.h
|
|-build      <---------------- Scroll down for # Building My_Torch_Project

Project CMake file

This file requires the following in order. Since it is the main file, the order is important.

  • enable_testing() is required at the top of file
  • Torch Settings are required before executables can be added
  • Any executable with torch dependency will need to follow the pattern in Main Executable
  • Finally, at the end-of-file, add the block as specified in REMOVE WINDOWS ERRORS.
cmake_minimum_required (VERSION X.X) #Usually the latest one you are using
project(
        My_Torch_Project
        VERSION X.Y.Z
        DESCRIPTION "My Torch Project")

# --------- Optionally enable standards ---------
# ------------------ STANDARDS ------------------
enable_language(C)
enable_language(CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
enable_testing()     # --- This is placed specifically at the top of the file to enable testing

# ------------------ Path Settings ------------------
set(MAIN_PATH "${CMAKE_SOURCE_DIR}") # ------- Makes source dir
set(CMAKE_PREFIX_PATH "${MAIN_PATH}/external/libtorch")
set(ANOTHER_DEPENDENCY_PATH "${MAIN_PATH}/external/another_dependency")
set(SRC "${MAIN_PATH}/src")

# ------------------ Torch Settings ------------------
include_directories("${MAIN_PATH}/external/libtorch")
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

# -------------------- Add Tests Subdirectory --------------------
add_subdirectory(${SRC}/test)

# ------------------ Main Executable ------------------
add_executable (MY_MAIN_EXECUTABLE "${SRC}/main.cpp" "${SRC}/main.h")
target_link_libraries(MY_MAIN_EXECUTABLE "${TORCH_LIBRARIES}")

# -------------------- REMOVE WINDOWS ERRORS --------------------
# The following code block is suggested to be used on Windows.
# According to https://github.com/pytorch/pytorch/issues/25457,
# the DLLs need to be copied to avoid memory errors.
if (MSVC)
        file(GLOB TORCH_DLLS "${TORCH_INSTALL_PREFIX}/lib/*.dll")
        add_custom_command(TARGET MY_MAIN_EXECUTABLE 
                        POST_BUILD
                        COMMAND ${CMAKE_COMMAND} -E copy_if_different
                        ${TORCH_DLLS}
                        $<TARGET_FILE_DIR:MY_MAIN_EXECUTABLE >)
endif (MSVC)

Test CMake file

This is for adding what tests we will be running. If we do not want to run test_2, we can simply comment it out

add_subdirectory(test_1)
add_subdirectory(test_2)
# add_subdirectory(test_3) This test is no longer detected

Test_1 CMake file

add_executable(TEST_1_EXEC_NAME "test_1.cpp" "test_1.h")

add_test(NAME 1_ST_TEST_ON__TEST_1_EXEC
        COMMAND $<TARGET_FILE:TEST_1_EXEC_NAME> 12.5 "arg2" "arg3" # -- These are args passed to the test, of course optional
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        )

add_test(NAME 2_ND_TEST_ON__TEST_1_EXEC
        COMMAND $<TARGET_FILE:TEST_1_EXEC_NAME>  # -- This test has no args passed to the executable
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        )

add_test(NAME 3_RD_TEST_ON__TEST_1_EXEC
        COMMAND $<TARGET_FILE:TEST_1_EXEC_NAME> 1.51 "arg2" "arg3" # -- These are args passed to the test, of course optional
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        )

Test_2 CMake file >> Depends on "torch/torch.h"

add_executable(TEST_2_EXEC_NAME "test_2.cpp" "test_2.h")

# --------------------- Tests ---------------------
add_test(NAME 1_ST_TEST_ON__TEST_1_EXEC
        COMMAND $<TARGET_FILE:TEST_1_EXEC_NAME> 12.5 "arg2" # -- These are args passed to the test, of course optional
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        )

add_test(NAME 2_ND_TEST_ON__TEST_1_EXEC
        COMMAND $<TARGET_FILE:TEST_1_EXEC_NAME> 1.51 "arg2" "arg3" # -- These are args passed to the test, of course optional
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        )

# ----------------------------------------------------------
# -- Add this to block to each CMakeLists.txt file which  -- 
# -- depends on torch for running tests. For Example,     --
# -- If it includes a `#include <torch/torch.h>`          --
# ----------------------------------------------------------
include_directories("${MAIN_PATH}/external/libtorch")
find_package(Torch REQUIRED)
target_link_libraries(TEST_2_EXEC_NAME "${TORCH_LIBRARIES}")

# According to https://github.com/pytorch/pytorch/issues/25457
if (MSVC)
  file(GLOB TORCH_DLLS "${TORCH_INSTALL_PREFIX}/lib/*.dll")
  add_custom_command(TARGET TEST_2_EXEC_NAME 
                     POST_BUILD
                     COMMAND ${CMAKE_COMMAND} -E copy_if_different
                     ${TORCH_DLLS}
                     $<TARGET_FILE_DIR:TEST_2_EXEC_NAME >)
endif (MSVC)
# ----------------------------------------------------------

Building and Running My_Torch_Project

We can now build the project. Lets iterate the project structure.

Steps to build:

  1. Create a directory for building the project

    My_Torch_Project~$ mkdir build
    My_Torch_Project~$ cd build
  2. Generate project files

    My_Torch_Project/build~$ cmake ..
  3. Open Command Pallet (Ctrl+Shift+P) and run CMake: Build . This will generate the executables in build/Debug (or Release, etc. See the OUTPUT window for exact commands).

  4. To run tests click on the CMake explorer in the Activity bar. Right click and see options. You can build, debug or run in terminal, etc.

  5. The main executable is stored in build/Debug/MY_MAIN_EXECUTABLE.exe and tests in build/src/test/test_1/Debug/TEST_1_EXEC_NAME.exe, etc.

  6. To easily run these, use the CMake explorer and right-click to show the options. Select Run in Terminal to see the output of the test or the executable.

Now The folder structure is something like this:

My_Torch_Project
  |
  |-CMakeLists.txt <--------------- {Project} CMakeLists.txt
  |-external/*
  |-src/*
  |-test
  |    |-CMakeLists.txt
  |    |-test_1/*
  |    |-test_2/*
  |
  |-build/*

Full clean and then Build

To completely clean the project and rebuild, go to root dir and remove all files.

My_Torch_Project~$ rm -rf build/* # removes all files
My_Torch_Project~$ cd build
My_Torch_Project/build~$ cmake .. # rebuild project

# You can hit **`CMake:Build`** command in the command pallet after this.
# All the tests and executables will be regenerated and be available to the CMake extension.

Testing program in terminal

Go to the build/Debug and run the main executable: MY_MAIN_EXECUTABLE.exe

Go to the build/src/test/test2/Debug and run: TEST_2_EXEC_NAME.exe

if main.cpp has the following...

#pragma warning(disable : 4624) // Torch warnings
#pragma warning(disable : 4805) // Torch warnings
#pragma warning(disable : 4067) // Torch warnings

#include <iostream>
#include "main.h"
#include <torch/torch.h>

int main()
{
    std::cout << "\nRunning Test file -> " << __FILE__ << std::endl;
    std::cout << torch::randn({3, 2}) << std::endl;
    return 0;
}

We will get the following output:

My_Torch_Project/build/Debug~$ MY_MAIN_EXECUTABLE.exe

Running Test file -> C:/My_Torch_Project/src/main.cpp
 1.0816 -1.2137
 0.2768 -0.5250
 0.3836  2.9232
[ CPUFloatType{3,2} ]

EASY MODE: After Initial Setup

On the status bar right-click and enable CMake Tools (Extension). This helps to select targets, build targets (for Debug, Release, MiniSizeRel, RelwithDebInfo), run tests, run built files in the terminal, etc. Makes life easier 😅.


MISC

Disable Common Warnings

To disable common warnings, place these in the .cpp or the .h files.

// To suppress those torch annoying when building with CMake
#pragma warning(disable : 4624) // Class Destructor Not visible
#pragma warning(disable : 4805) // Comparing bool and int
#pragma warning(disable : 4067) // Extra /Za preprocessor command
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment