diff --git a/mediapipe/pose_tracking_dll/BUILD b/mediapipe/pose_tracking_dll/BUILD new file mode 100644 index 000000000..cce8f7357 --- /dev/null +++ b/mediapipe/pose_tracking_dll/BUILD @@ -0,0 +1,52 @@ +# Copyright 2020 The MediaPipe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("windows_dll_library.bzl", "windows_dll_library") +licenses(["notice"]) + +package(default_visibility = ["//mediapipe/examples:__subpackages__"]) + +# Define the shared library +windows_dll_library( + name = "pose_tracking_lib", + srcs = ["pose_tracking.cpp"], + hdrs = ["pose_tracking.h"], + # Define COMPILING_DLL to export symbols during the DLL compilation. + copts = ["-DCOMPILING_DLL"], + deps = [ + "//mediapipe/framework:calculator_framework", + "//mediapipe/framework/formats:image_frame", + "//mediapipe/framework/formats:image_frame_opencv", + "//mediapipe/framework/formats:landmark_cc_proto", + "//mediapipe/framework/formats:rect_cc_proto", + "//mediapipe/framework/port:file_helpers", + "//mediapipe/framework/port:parse_text_proto", + "//mediapipe/framework/port:status", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + + "//mediapipe/graphs/pose_tracking:pose_tracking_cpu_deps", + ] +) + +# **Implicitly link to face_mesh_lib.dll** +cc_binary( + name = "pose_tracking_cpu", + linkopts = ["/FORCE:MULTIPLE"], + deps = [ + "//mediapipe/examples/desktop:demo_run_graph_main", + "//mediapipe/graphs/pose_tracking:pose_tracking_cpu_deps", + ":pose_tracking_lib" + ], +) diff --git a/mediapipe/pose_tracking_dll/README.md b/mediapipe/pose_tracking_dll/README.md new file mode 100644 index 000000000..d1e4912c5 --- /dev/null +++ b/mediapipe/pose_tracking_dll/README.md @@ -0,0 +1,133 @@ +# Description + +The pose_tracking_dll module allows for building a Mediapipe-based pose tracking DLL library that can be used with any C++ project. All the dependencies such as tensorflow are built statically into the dll. + +Currently, the following features are supported: +- Segmenting the person(s) of interest +- Segmenting the skeleton(s) +- Accessing the 3D coordinates of each node of the skeleton + +# Prerequisites + +Install Mediapipe development environment as follows. + +## Remarks + +This guide assumes a Nimagna development environment. + +Otherwise, please also read the guidelines on the official Mediapipe website: https://google.github.io/mediapipe/getting_started/install.html#installing-on-windows. + +## MSYS2 + +- Install MSYS2 from https://www.msys2.org/ (tested with version 20230127) + - The MSYS2 installation path is referred to as `MSYS2DIR` below. +- Install necessary packages: + - `pacman -S git patch unzip` and confirm installation + +## Python 3.11 + +- Install Python 3.11 + - Download Python 3.11.x Windows executable from https://www.python.org/downloads/windows/ + - Allow the installer to edit the %PATH% environment variable. + - Note: Newer Python version have not been tested + - The Python installation path is referred to as `PYTHONDIR` below. + - Usually, this is `C:\Users\...\AppData\Local\Programs\Python\Python311` when installing only for the current user. + - Run `pip install numpy` in a new command line. + +## Install Visual C++ Build Tools 2019 and WinSDK + +- Install Visual C++ Build Tools 2019 with WinSDK + - Download and install Visual C++ Build Tools 2019 (16.11 used here) from https://my.visualstudio.com/Downloads?q=visual%20studio%202019%20build&wt.mc_id=o~msft~vscom~older-downloads (if link does not work, use https://visualstudio.microsoft.com/visual-cpp-build-tools/ and search for "older versions" to find the 2019 installer) + - Install with + - "Desktop Development with C++" + - Individual components: select "Windows 10 SDK (10.0.19041.0)" + ![image](https://user-images.githubusercontent.com/83065859/148920359-fc5830c2-3eb1-47d4-ba33-8b1ba783b728.png) + - Note: VC Build Tools 2022 or newer WinSDK versions do not compile with the current code base. + +## Install Bazel 5.4.0 + +- Download `bazel-5.4.0-windows-x86_64.exe` from https://github.com/bazelbuild/bazel/releases/tag/5.4.0 +- Put file into a folder and rename it to `bazel.exe` +- The Bazel installation path is referred to as `BAZEL_PATH` below. + +## Install OpenCV + +- Download OpenCV 3.4.10 from https://sourceforge.net/projects/opencvlibrary/files/3.4.10/opencv-3.4.10-vc14_vc15.exe/download +- Extract OpenCV into a separate folder. This folder is referred to as `OPENCVDIR` in the following steps. + +## Checkout Mediapipe + +- `git clone https://github.com/NimagnaAG/mediapipe` +- The repository root folder is referred to as `MEDIAPIPEDIR` below. + +## Prepare Build + +- Edit the `MEDIAPIPEDIR\WORKSPACE` file: + - Around line 215, is the "windows_opencv" repository. + - Adapt the path to point to `OPENCVDIR\\build` (using double backslashes): + ``` + new_local_repository( + name = "windows_opencv", + build_file = "@//third_party:opencv_windows.BUILD", + path = "OPENCVDIR\\build", + ) + ``` +- Edit the `MEDIAPIPEDIR\mediapipe\pose_tracking_dll\build.bat` file + - Must change: + - `BAZEL_PATH` -> path to bazel.exe (No default) + - Build configuration + - `MEDIAPIPE_CONFIGURATION` -> Release (Default, `opt`) or Debug (`dbg`) + - Verify: + - `MYSYS_PATH` -> path to `MSYS2DIR\usr\bin` (Default: `C:\msys64\usr\bin`) + - `BAZEL_SH` -> path to bash.exe (Default: `%MYSYS_PATH%\bash.exe`) + - `BAZEL_VS_VERSION` -> Visual Studio version (Default: `2019`) + - `BAZEL_VC_FULL_VERSION` -> Visual Studio Build Tools full version. Depends on the version installed. See `See C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC` + - `BAZEL_WINSDK_FULL_VERSION` -> WinSDK version (Default: `10.0.19041.0`) + - `BAZEL_PYTHON_PATH` -> Path to python.exe (Default: `%LOCALAPPDATA_FORWARDSLASH%/Programs/Python/Python311/python.exe`) + - Optional + - `BAZEL_TMP_BUILD_DIR` -> A temporary build folder + - `TARGET_PATH` -> A target folder to copy the relevant files to, i.e. the mediapipe/version folder of the external repo + +# Build + +- Open a Command Prompt +- `cd MEDIAPIPEDIR` +- `mediapipe\pose_tracking_dll\build.bat` ... and take a break! +- The build output can be found in the `MEDIAPIPEDIR\bazel-bin\mediapipe\pose_tracking_dll` folder. + +# How to use the DLL + +- Go to bazel-bin\mediapipe\pose_tracking_dll +- Link `pose_tracking_cpu.lib` and `pose_tracking_lib.dll.if.lib` statically in your project. +- Make sure `opencv_world3410.dll` and `pose_tracking_lib.dll` are accessible in your executable's DLL search path. +- Include `mediapipe\pose_tracking_dll\pose_tracking.h` header file to access the methods of the library. + +# Troubleshooting + +## Different OpenCV version +- If you are using a **different OpenCV version**, adapt the `OPENCV_VERSION` variable in the file `mediapipe/external/opencv_.BUILD` to the one installed in the system (https://github.com/google/mediapipe/issues/1926#issuecomment-825874197). + +## Bazel issues + +- If bazel fails to download packages + - run `bazel clean --expunge` and try again. +- If bazel fails with an `fatal error C1083: Cannot open compiler generated file: '': Invalid argument`, your [path is too long](https://stackoverflow.com/questions/34074925/vs-2015-cannot-open-compiler-generated-file-invalid-argument). + - set `BAZEL_TMP_BUILD_DIR` in the batch file to a temporary folder with a short path + - Note: Clean the bazel environment becomes `bazel --output_base=%BAZEL_TMP_BUILD_DIR% clean --expunge` + +## Stalled build process + +In the case the build stalls, pressing Ctrl+C might not be sufficient to stop the task. In that case, if you try to (resume the) build again, +the following message will be displayed: + +``` +Another command (pid=5300) is running. Waiting for it to complete on the server (server_pid=3684) +``` + +Unfortunately this process is hidden for some reason and can't be found in taskmgr. Fortunately, you can use the `taskkill` command to kill the process: + +``` +taskkill /F /PID 3684 +``` + +After that, you should be able to run the build command again. diff --git a/mediapipe/pose_tracking_dll/build.bat b/mediapipe/pose_tracking_dll/build.bat new file mode 100644 index 000000000..d40f04330 --- /dev/null +++ b/mediapipe/pose_tracking_dll/build.bat @@ -0,0 +1,83 @@ +@echo off +setlocal ENABLEDELAYEDEXPANSION + +:: ---------------------------------------------------------- +:: Do not change +:: ---------------------------------------------------------- + +:: needs to be run from repo root +if NOT EXIST mediapipe\pose_tracking_dll\pose_tracking.cpp ( + echo Batch file must be run from repository root, i.e. mediapipe\pose_tracking_dll\build.bat + EXIT +) +set "LOCALAPPDATA_FORWARDSLASH=%LOCALAPPDATA:\=/%" + +:: ---------------------------------------------------------- +:: Adapt the variables below to your local environment +:: ---------------------------------------------------------- + + +:: path to bazel.exe +SET BAZEL_PATH=E:\repos\bazel\5.4.0 + +:: path to msys +SET MYSYS_PATH=C:\msys64\usr\bin + +:: path to msys bash +SET BAZEL_SH=%MYSYS_PATH%\bash.exe + +:: Visual Studio C++ Build Tools +SET BAZEL_VS_VERSION=2019 +SET BAZEL_VS=C:\Program Files (x86)\Microsoft Visual Studio\%BAZEL_VS_VERSION%\BuildTools +SET BAZEL_VC=%SBAZEL_VS%\VC + +:: Visual Studio C++ Build Tools version +:: See C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC +SET BAZEL_VC_FULL_VERSION=14.29.30133 + +:: Windows SDK version +SET BAZEL_WINSDK_FULL_VERSION=10.0.19041.0 + +:: full path to python.exe +SET BAZEL_PYTHON_PATH=%LOCALAPPDATA_FORWARDSLASH%/Programs/Python/Python311/python.exe + +:: Optional: temporary build path +SET BAZEL_TMP_BUILD_DIR=E:\repos\mp_output + +:: Release [opt] or Debug [dbg] +SET MEDIAPIPE_CONFIGURATION=opt + +:: Optional: A target path to copy the relevant files after build, i.e. the version folder of the external repo +SET TARGET_PATH=C:\Users\ChristophNiederberge\source\repos\CodeReviews\external\mediapipe\0.8.10.2_x64 + +:: ---------------------------------------------------------- +:: Build posetracking DLL +:: ---------------------------------------------------------- + +IF NOT [%BAZEL_TMP_BUILD_DIR%]==[] ( + ECHO Using temporary build directory: %BAZEL_TMP_BUILD_DIR% + bazel --output_base "%BAZEL_TMP_BUILD_DIR%" build -c %MEDIAPIPE_CONFIGURATION% --define MEDIAPIPE_DISABLE_GPU=1 --action_env PYTHON_BIN_PATH="%BAZEL_PYTHON_PATH%" mediapipe/pose_tracking_dll:pose_tracking_cpu +) ELSE ( + bazel build -c %MEDIAPIPE_CONFIGURATION% --define MEDIAPIPE_DISABLE_GPU=1 --action_env PYTHON_BIN_PATH="%BAZEL_PYTHON_PATH%" mediapipe/pose_tracking_dll:pose_tracking_cpu +) + +:: ---------------------------------------------------------- +:: Copy files to target folder (optional) +:: ---------------------------------------------------------- +IF NOT [%TARGET_PATH%]==[] ( + IF [%MEDIAPIPE_CONFIGURATION%]==[opt] ( + ECHO Copy files to %TARGET_PATH%\x64\Release ... + mkdir %TARGET_PATH%\x64\Release + copy bazel-bin\mediapipe\pose_tracking_dll\pose_tracking_lib.dll %TARGET_PATH%\x64\Release + copy bazel-bin\mediapipe\pose_tracking_dll\pose_tracking_lib.dll.if.lib %TARGET_PATH%\x64\Release + copy bazel-bin\mediapipe\pose_tracking_dll\opencv_world3410.dll %TARGET_PATH%\x64\Release + ) + IF [%MEDIAPIPE_CONFIGURATION%]==[dbg] ( + ECHO Copy files to %TARGET_PATH%\x64\Debug ... + mkdir %TARGET_PATH%\x64\Debug + copy bazel-bin\mediapipe\pose_tracking_dll\pose_tracking_lib.dll %TARGET_PATH%\x64\Debug + copy bazel-bin\mediapipe\pose_tracking_dll\pose_tracking_lib.dll.if.lib %TARGET_PATH%\x64\Debug + copy bazel-bin\mediapipe\pose_tracking_dll\pose_tracking_lib.pdb %TARGET_PATH%\x64\Debug + copy bazel-bin\mediapipe\pose_tracking_dll\opencv_world3410d.dll %TARGET_PATH%\x64\Debug + ) +) \ No newline at end of file diff --git a/mediapipe/pose_tracking_dll/pose_tracking.cpp b/mediapipe/pose_tracking_dll/pose_tracking.cpp new file mode 100644 index 000000000..5c3b6709c --- /dev/null +++ b/mediapipe/pose_tracking_dll/pose_tracking.cpp @@ -0,0 +1,170 @@ +/** + Copyright 2022, Nimagna AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "pose_tracking.h" + +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "mediapipe/framework/calculator_framework.h" +//#include "mediapipe/framework/formats/image_frame.h" +#include "mediapipe/framework/formats/image_frame_opencv.h" +#include "mediapipe/framework/formats/landmark.pb.h" +#include "mediapipe/framework/port/file_helpers.h" +//#include "mediapipe/framework/port/opencv_highgui_inc.h" +//#include "mediapipe/framework/port/opencv_imgproc_inc.h" +//#include "mediapipe/framework/port/opencv_video_inc.h" +#include "mediapipe/framework/port/parse_text_proto.h" +#include "mediapipe/framework/port/status.h" + +class PoseTrackingImpl { + public: + PoseTrackingImpl(const std::string& calculatorGraphConfigFile) { + auto status = initialize(calculatorGraphConfigFile); + LOG(WARNING) << "Initialized PoseTracking with status: " << status; + } + + absl::Status initialize(const std::string& calculatorGraphConfigFile) { + std::string graphContents; + MP_RETURN_IF_ERROR(mediapipe::file::GetContents(calculatorGraphConfigFile, &graphContents)); + + mediapipe::CalculatorGraphConfig config = + mediapipe::ParseTextProtoOrDie(graphContents); + + MP_RETURN_IF_ERROR(graph.Initialize(config)); + ASSIGN_OR_RETURN(mediapipe::OutputStreamPoller poller, + graph.AddOutputStreamPoller(kOutputSegmentationStream, true)); + + ASSIGN_OR_RETURN(mediapipe::OutputStreamPoller landmarksPoller, + graph.AddOutputStreamPoller(kOutpuLandmarksStream, true)); + + + maskPollerPtr = std::make_unique(std::move(poller)); + + landmarksPollerPtr = + std::make_unique(std::move(landmarksPoller)); + + + MP_RETURN_IF_ERROR(graph.StartRun({})); + } + + bool processFrame(const cv::Mat& inputRGB8Bit) { + // Wrap Mat into an ImageFrame. + auto inputFrame = absl::make_unique( + mediapipe::ImageFormat::SRGB, inputRGB8Bit.cols, inputRGB8Bit.rows, + mediapipe::ImageFrame::kDefaultAlignmentBoundary); + cv::Mat inputFrameMat = mediapipe::formats::MatView(inputFrame.get()); + inputRGB8Bit.copyTo(inputFrameMat); + + // Send image packet into the graph. + size_t frameTimestampUs = + static_cast(cv::getTickCount()) / static_cast(cv::getTickFrequency()) * 1e6; + auto status = graph.AddPacketToInputStream( + kInputStream, + mediapipe::Adopt(inputFrame.release()).At(mediapipe::Timestamp(frameTimestampUs))); + + if (!status.ok()) { + LOG(WARNING) << "Graph execution failed: " << status; + return false; + } + + // Get the graph result packet, or stop if that fails. + mediapipe::Packet maskPacket; + if (!maskPollerPtr || !maskPollerPtr->Next(&maskPacket) || maskPacket.IsEmpty()) return false; + auto& outputFrame = maskPacket.Get(); + + // Get pose landmarks. + if (!landmarksPollerPtr || !landmarksPollerPtr->Next(&poseLandmarksPacket)) { + return false; + } + + // Convert back to opencv for display or saving. + auto mask = mediapipe::formats::MatView(&outputFrame); + segmentedMask = mask.clone(); + + absl::Status landmarksStatus = detectLandmarksWithStatus(poseLandmarks); + + return landmarksStatus.ok(); + } + + absl::Status detectLandmarksWithStatus(nimagna::cv_wrapper::Point3f* poseLandmarks) { + if (poseLandmarksPacket.IsEmpty()) { + return absl::CancelledError("Pose landmarks packet is empty."); + } + + auto retrievedLandmarks = poseLandmarksPacket.Get<::mediapipe::NormalizedLandmarkList>(); + + // Convert landmarks to cv::Point3f**. + const auto landmarksCount = retrievedLandmarks.landmark_size(); + + for (int j = 0; j < landmarksCount; ++j) { + const auto& landmark = retrievedLandmarks.landmark(j); + poseLandmarks[j].x = landmark.x(); + poseLandmarks[j].y = landmark.y(); + poseLandmarks[j].z = landmark.z(); + visibility[j] = landmark.visibility(); + } + + return absl::OkStatus(); + } + + nimagna::cv_wrapper::Point3f* lastDetectedLandmarks() { return poseLandmarks; } + + cv::Mat lastSegmentedFrame() { return segmentedMask; } + float* landmarksVisibility() { return visibility; } + + static constexpr size_t kLandmarksCount = 33u; + + private: + mediapipe::Packet poseLandmarksPacket; + cv::Mat segmentedMask; + nimagna::cv_wrapper::Point3f poseLandmarks[kLandmarksCount]; + float visibility[kLandmarksCount] = {0}; + std::unique_ptr maskPollerPtr; + std::unique_ptr landmarksPollerPtr; + mediapipe::CalculatorGraph graph; + const char* kInputStream = "input_video"; + const char* kOutputSegmentationStream = "segmentation_mask"; + const char* kOutpuLandmarksStream = "pose_landmarks"; +}; + +namespace nimagna { +PoseTracking::PoseTracking(const char* calculatorGraphConfigFile) { + mImplementation = new PoseTrackingImpl(calculatorGraphConfigFile); +} + +bool PoseTracking::processFrame(const cv_wrapper::Mat& inputRGB8Bit) { + const auto frame = cv::Mat(inputRGB8Bit.rows, inputRGB8Bit.cols, CV_8UC3, inputRGB8Bit.data); + return mImplementation->processFrame(frame); +} + +PoseTracking::PoseLandmarks PoseTracking::lastDetectedLandmarks() { + return {mImplementation->lastDetectedLandmarks(), mImplementation->landmarksVisibility()}; +} + +cv_wrapper::Mat PoseTracking::lastSegmentedFrame() { + const cv::Mat result = mImplementation->lastSegmentedFrame(); + + return cv_wrapper::Mat(result.rows, result.cols, result.data); +} + +PoseTracking::~PoseTracking() +{ + delete mImplementation; +} +} // namespace nimagna diff --git a/mediapipe/pose_tracking_dll/pose_tracking.h b/mediapipe/pose_tracking_dll/pose_tracking.h new file mode 100644 index 000000000..b40925185 --- /dev/null +++ b/mediapipe/pose_tracking_dll/pose_tracking.h @@ -0,0 +1,124 @@ +/** + Copyright 2022, Nimagna AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef POSE_TRACKING_LIBRARY_H +#define POSE_TRACKING_LIBRARY_H + +#ifdef COMPILING_DLL +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __declspec(dllimport) +#endif + +class PoseTrackingImpl; + +namespace nimagna { +namespace cv_wrapper { +struct Point2f { + float x = 0; + float y = 0; + + Point2f() = default; + Point2f(float x, float y) : x(x), y(y) {} +}; +struct Point3f { + float x = 0; + float y = 0; + float z = 0; + + Point3f() = default; + Point3f(float x, float y, float z) : x(x), y(y), z(z) {} +}; + +struct Rect { + int x = 0; + int y = 0; + int width = 0; + int height = 0; + + Rect() = default; + Rect(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) {} +}; + +struct Mat { + int rows = 0; + int cols = 0; + unsigned char* data = 0; + + Mat(int rows, int cols, unsigned char* data) : rows(rows), cols(cols), data(data) {} +}; +} // namespace cv_wrapper + + +class DLLEXPORT PoseTracking { + public: + struct PoseLandmarks { + PoseLandmarks(cv_wrapper::Point3f* points, float* visibility) : points(points), visibility(visibility) {} + static constexpr size_t kLandmarksCount = 33u; + const cv_wrapper::Point3f* points; + const float* visibility; + }; + + enum LandmarkNames { + NOSE = 0, + LEFT_EYE_INNER, + LEFT_EYE, + LEFT_EYE_OUTER, + RIGHT_EYE_INNER, + RIGHT_EYE, + RIGHT_EYE_OUTER, + LEFT_EAR, + RIGHT_EAR, + MOUTH_LEFT, + MOUTH_RIGHT, + LEFT_SHOULDER, + RIGHT_SHOULDER, + LEFT_ELBOW, + RIGHT_ELBOW, + LEFT_WRIST, + RIGHT_WRIST, + LEFT_PINKY, + RIGHT_PINKY, + LEFT_INDEX, + RIGHT_INDEX, + LEFT_THUMB, + RIGHT_THUMB, + LEFT_HIP, + RIGHT_HIP, + LEFT_KNEE, + RIGHT_KNEE, + LEFT_ANKLE, + RIGHT_ANKLE, + LEFT_HEEL, + RIGHT_HEEL, + LEFT_FOOT_INDEX, + RIGHT_FOOT_INDEX, + COUNT = PoseLandmarks::kLandmarksCount + }; + + PoseTracking(const char* calculatorGraphConfigFile); + ~PoseTracking(); + + bool processFrame(const cv_wrapper::Mat& inputRGB8Bit); + cv_wrapper::Mat lastSegmentedFrame(); + PoseTracking::PoseLandmarks lastDetectedLandmarks(); + + private: + PoseTrackingImpl* mImplementation; +}; +} // namespace nimagna + +#endif diff --git a/mediapipe/pose_tracking_dll/windows_dll_library.bzl b/mediapipe/pose_tracking_dll/windows_dll_library.bzl new file mode 100644 index 000000000..ef7371af8 --- /dev/null +++ b/mediapipe/pose_tracking_dll/windows_dll_library.bzl @@ -0,0 +1,62 @@ +""" +This is a simple windows_dll_library rule for builing a DLL Windows +that can be depended on by other cc rules. +Example useage: + windows_dll_library( + name = "hellolib", + srcs = [ + "hello-library.cpp", + ], + hdrs = ["hello-library.h"], + # Define COMPILING_DLL to export symbols during compiling the DLL. + copts = ["/DCOMPILING_DLL"], + ) +""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library") + +def windows_dll_library( + name, + srcs = [], + deps = [], + hdrs = [], + visibility = None, + **kwargs): + """A simple windows_dll_library rule for builing a DLL Windows.""" + dll_name = name + ".dll" + import_lib_name = name + "_import_lib" + import_target_name = name + "_dll_import" + + # Build the shared library + cc_binary( + name = dll_name, + srcs = srcs + hdrs, + deps = deps, + linkshared = 1, + **kwargs + ) + + # Get the import library for the dll + native.filegroup( + name = import_lib_name, + srcs = [":" + dll_name], + output_group = "interface_library", + ) + + # Because we cannot directly depend on cc_binary from other cc rules in deps attribute, + # we use cc_import as a bridge to depend on the dll. + cc_import( + name = import_target_name, + interface_library = ":" + import_lib_name, + shared_library = ":" + dll_name, + ) + + # Create a new cc_library to also include the headers needed for the shared library + cc_library( + name = name, + hdrs = hdrs, + visibility = visibility, + deps = deps + [ + ":" + import_target_name, + ], + )