Merge branch '0.8.10.2_windows' into 0.9.1_windows

This commit is contained in:
Christoph Niederberger 2023-02-15 10:08:18 +01:00
commit c63a1dcc73
6 changed files with 624 additions and 0 deletions

View File

@ -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"
],
)

View File

@ -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_<platform>.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.

View File

@ -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
)
)

View File

@ -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 <cstdlib>
#include <string>
#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<mediapipe::CalculatorGraphConfig>(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<mediapipe::OutputStreamPoller>(std::move(poller));
landmarksPollerPtr =
std::make_unique<mediapipe::OutputStreamPoller>(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::ImageFrame>(
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<double>(cv::getTickCount()) / static_cast<double>(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<mediapipe::ImageFrame>();
// 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<mediapipe::OutputStreamPoller> maskPollerPtr;
std::unique_ptr<mediapipe::OutputStreamPoller> 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

View File

@ -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

View File

@ -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,
],
)