Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mavsdk: add mavlink and mavsdk recipes #26136

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions recipes/mavlink/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
sources:
"1.0.12.cci.20241205":
mavlink:
url: "https://github.com/mavlink/mavlink/archive/35f70c4a7e0c4aa91edc1eaa5205a1077490442c.tar.gz"
sha256: "be2e9583bc72cc894056b903578879128fe8c68a92fbcbb3268ab92c78c7ddef"
pymavlink:
url: "https://github.com/ArduPilot/pymavlink/archive/refs/tags/v2.4.42.tar.gz"
sha256: "bbe1b78759211597c98214e31b6dfc9cc42b3cb4548c813674463cb664b56a9f"
"1.0.12.cci.20240530":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this specific commit back in May?
For a new recipe, without upstream release, I think starting with just a current commit would be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the mavlink version used by the latest mavsdk. The latest mavlink version (which is also included in the recipe) was causing issues, if I remember correctly.

mavlink:
url: "https://github.com/mavlink/mavlink/archive/f1d42e2774cae767a1c0651b0f95e3286c587257.tar.gz"
sha256: "3eb515843143fd9b1e275141c4c82f5f3cbbb77c12e1eb2b929a6a005f016a51"
pymavlink:
url: "https://github.com/ArduPilot/pymavlink/archive/refs/tags/v2.4.42.tar.gz"
sha256: "bbe1b78759211597c98214e31b6dfc9cc42b3cb4548c813674463cb664b56a9f"
86 changes: 86 additions & 0 deletions recipes/mavlink/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import os

from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import copy, get, rmdir

required_conan_version = ">=2.4"


class MavlinkConan(ConanFile):
name = "mavlink"
description = "Marshalling / communication library for drones."
license = "MIT"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/mavlink/mavlink"
topics = ("mav", "drones", "marshalling", "communication")
package_type = "header-library"
settings = "os", "arch", "compiler", "build_type"
options = {
# https://mavlink.io/en/messages/README.html
"dialect": [
"all",
"common",
"standard",
"minimal",
"development",
"ardupilotmega",
"ASLUAV",
"AVSSUAS",
"csAirLink",
"cubepilot",
"icarous",
"loweheiser",
"matrixpilot",
"paparazzi",
"storm32",
"ualberta",
"uAvionix",
],
# https://github.com/ArduPilot/pymavlink/blob/v2.4.42/tools/mavgen.py#L24
"wire_protocol": ["0.9", "1.0", "2.0"],
}
default_options = {
"dialect": "common",
"wire_protocol": "2.0",
}
languages = ["C"]

def layout(self):
cmake_layout(self, src_folder="src")

def package_id(self):
self.info.clear()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This package is not independent of the options.dialect. Having different dialect means generating different headers, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Thanks! Limited it to just settings.


def build_requirements(self):
self.tool_requires("cpython/[>=3.12 <4]")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But pymavlink requires other transitive dependencies that will not be found: https://github.com/ArduPilot/pymavlink/blob/master/requirements.txt, this will most likely fail.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested this and it indeed fails:

CUSTOMBUILD : error : Could not find a version that satisfies the requirement lxml>=3.6.0 (from versions: none) [C:\Users\memsharded\.conan2\p\b\mavli7342ae94e4fe c\b\build\generate_c_headers.vcxproj]

This seems quite a challenge to me.

Copy link
Contributor Author

@valgur valgur Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced the pip install ... && python -m pymavlink.tools.mavgen ... call via CMake with a direct self.run() for a better control over the temporary Python env. A temporary site-packages folder is created in the build folder, and caching is disabled to not pollute ~/.cache/pip.

I have used the same pattern for Python build-time deps in a few other recipes and it has worked without issues, afaik:


def source(self):
info = self.conan_data["sources"][self.version]
get(self, **info["mavlink"], strip_root=True)
get(self, **info["pymavlink"], strip_root=True, destination="pymavlink")

def generate(self):
tc = CMakeToolchain(self)
tc.cache_variables["MAVLINK_DIALECT"] = self.options.dialect
tc.cache_variables["MAVLINK_VERSION"] = self.options.wire_protocol
tc.generate()
deps = CMakeDeps(self)
deps.generate()

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
copy(self, "COPYING", self.source_folder, os.path.join(self.package_folder, "licenses"))
cmake = CMake(self)
cmake.install()
rmdir(self, os.path.join(self.package_folder, "lib"))

def package_info(self):
self.cpp_info.set_property("cmake_file_name", "MAVLink")
self.cpp_info.set_property("cmake_target_name", "MAVLink::mavlink")
self.cpp_info.bindirs = []
self.cpp_info.libdirs = []
7 changes: 7 additions & 0 deletions recipes/mavlink/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES C)

find_package(MAVLink REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.c)
target_link_libraries(${PROJECT_NAME} PRIVATE MAVLink::mavlink)
25 changes: 25 additions & 0 deletions recipes/mavlink/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMake
import os


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeDeps", "CMakeToolchain"

def layout(self):
cmake_layout(self)

def requirements(self):
self.requires(self.tested_reference_str)

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
5 changes: 5 additions & 0 deletions recipes/mavlink/all/test_package/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
versions:
"1.2.0":
folder: all
"1.1.0":
folder: all
7 changes: 7 additions & 0 deletions recipes/mavlink/all/test_package/test_package.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <mavlink/minimal/mavlink.h>

#include <stdio.h>

int main() {
printf("Payload size for minimal dialect: %d bytes\n", MAVLINK_MAX_DIALECT_PAYLOAD_SIZE);
}
5 changes: 5 additions & 0 deletions recipes/mavlink/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
versions:
"1.0.12.cci.20241205":
folder: all
"1.0.12.cci.20240530":
folder: all
8 changes: 8 additions & 0 deletions recipes/mavsdk/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
sources:
"2.13.0":
source:
url: "https://github.com/mavlink/MAVSDK/archive/refs/tags/v2.13.0.tar.gz"
sha256: "9af60e71d707b0ca412198dc14ab7e1b632dd7f4558c2f5e7cefc0a0354ce3a6"
proto:
url: "https://github.com/mavlink/MAVSDK-Proto/archive/34bce6d61dba5f72b602bdbd31f04fceff093881.tar.gz"
sha256: "1f441671dddf38fe5ef6a4d0aa73be5634437a4e6bd516348e7f6e344ed05356"
163 changes: 163 additions & 0 deletions recipes/mavsdk/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import os

from conan import ConanFile
from conan.tools.build import check_min_cppstd
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import copy, get, rm, rmdir, replace_in_file
from conan.tools.microsoft import is_msvc
from conan.tools.scm import Version

required_conan_version = ">=2.0.9"


class MavsdkConan(ConanFile):
name = "mavsdk"
description = "C++ library to interface with MAVLink systems"
license = "BSD-3-Clause"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://mavsdk.mavlink.io/"
topics = ("mavlink", "drones")
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"regenerate_protobuf": [True, False],
"build_server": [True, False],
"enable_reflection": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"regenerate_protobuf": False,
"build_server": False,
"enable_reflection": False,
}
implements = ["auto_shared_fpic"]

def configure(self):
if self.options.shared:
self.options.rm_rf("fPIC")
if self.options.build_server:
# The .proto files were processed with protobuf v4, which is not compatible with
# the gRPC protobuf version on CCI, so we need to regenerate them.
del self.options.regenerate_protobuf
else:
del self.options.enable_reflection

def layout(self):
cmake_layout(self, src_folder="src")

def requirements(self):
self.requires("mavlink/1.0.12.cci.20240530", transitive_headers=True)
self.requires("jsoncpp/1.9.6")
self.requires("tinyxml2/10.0.0")
self.requires("libcurl/[>=7.86 <9]")
self.requires("xz_utils/[>=5.4.5 <6]")
if self.options.build_server:
self.requires("grpc/1.67.1")

def validate(self):
check_min_cppstd(self, 17)

def build_requirements(self):
if self.options.get_safe("regenerate_protobuf", True):
if self.options.build_server:
self.tool_requires("grpc/<host_version>")
self.tool_requires("protobuf/<host_version>")
else:
self.tool_requires("grpc/1.67.1")
self.tool_requires("protobuf/5.27.0")
if self.settings_build.os == "Windows":
self.win_bash = True
if not self.conf.get("tools.microsoft.bash:path", check_type=str):
self.tool_requires("msys2/cci.latest")

def source(self):
get(self, **self.conan_data["sources"][self.version]["source"], strip_root=True)
get(self, **self.conan_data["sources"][self.version]["proto"], strip_root=True, destination="proto")
# Let Conan handle the C++ standard
replace_in_file(self, os.path.join(self.source_folder, "src", "CMakeLists.txt"),
"set(CMAKE_CXX_STANDARD 17)", "")
# Fix version string for SOVERSION, since it cannot be derived from a git tag.
replace_in_file(self, os.path.join(self.source_folder, "CMakeLists.txt"),
'set(VERSION_STR "0.0.0")',
f'set(VERSION_STR "v{self.version}")')

def generate(self):
tc = CMakeToolchain(self)
if Version(self.version) <= "2.13.0":
tc.cache_variables["BUILD_TESTS"] = False
tc.cache_variables["BUILD_TESTING"] = False
tc.cache_variables["SUPERBUILD"] = False
tc.cache_variables["MAVLINK_DIALECT"] = self.dependencies["mavlink"].options.dialect
tc.cache_variables["BUILD_MAVSDK_SERVER"] = self.options.build_server
tc.cache_variables["BUILD_WITH_PROTO_REFLECTION"] = self.options.get_safe("enable_reflection", False)
# The project uses CMake policy version < 3.12 in several places
tc.cache_variables["CMAKE_POLICY_DEFAULT_CMP0077"] = "NEW"
tc.generate()

deps = CMakeDeps(self)
deps.generate()

def build(self):
if self.options.get_safe("regenerate_protobuf", True):
# No need to re-generate Jinja templates
replace_in_file(self, os.path.join(self.source_folder, "tools", "generate_from_protos.sh"),
"python3 ${script_dir}/grpc_server_jinja.py",
"# python3 ${script_dir}/grpc_server_jinja.py")
self.run(f"tools/generate_from_protos.sh -b {self.build_folder}", cwd=self.source_folder)
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
copy(self, "LICENSE.md", self.source_folder, os.path.join(self.package_folder, "licenses"))
cmake = CMake(self)
cmake.install()
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
rm(self, "*.pdb", self.package_folder, recursive=True)

def package_info(self):
self.cpp_info.set_property("cmake_file_name", "MAVSDK")

postfix = ""
if is_msvc(self) and self.settings.build_type == "Debug":
postfix = "d"

mavsdk = self.cpp_info.components["mavsdk"]
mavsdk.set_property("cmake_target_name", "MAVSDK::mavsdk")
mavsdk.set_property("pkg_config_name", "mavsdk")
mavsdk.libs = ["mavsdk" + postfix]
mavsdk.includedirs.append(os.path.join("include", "mavsdk"))
if self.settings.os in ["Linux", "FreeBSD"]:
mavsdk.system_libs = ["m", "pthread", "dl"]
elif self.settings.os == "Windows":
mavsdk.system_libs = ["ws2_32"]
elif self.settings.os == "iOS":
mavsdk.frameworks = ["Foundation", "Security"]
elif self.settings.os == "Android":
mavsdk.system_libs = ["log"]
if str(self.settings.compiler.libcxx) in ["libstdc++", "libstdc++11"] or str(self.settings.arch).startswith("arm"):
mavsdk.system_libs.append("atomic")
mavsdk.requires = [
"mavlink::mavlink",
"jsoncpp::jsoncpp",
"tinyxml2::tinyxml2",
"libcurl::libcurl",
"xz_utils::xz_utils",
]

if self.options.build_server:
mavsdk_server = self.cpp_info.components["mavsdk_server"]
mavsdk_server.set_property("cmake_target_name", "MAVSDK::mavsdk_server")
mavsdk_server.set_property("pkg_config_name", "mavsdk_server")
mavsdk_server.libs = ["mavsdk_server"]
if self.settings.os in ["Linux", "FreeBSD"]:
mavsdk_server.system_libs = ["dl"]
if str(self.settings.compiler.libcxx) in ["libstdc++", "libstdc++11"] or str(self.settings.arch).startswith("arm"):
mavsdk_server.system_libs.append("atomic")
mavsdk_server.requires = ["grpc::grpc++"]
if self.options.enable_reflection:
mavsdk_server.requires.append("grpc::grpc++_reflection")
7 changes: 7 additions & 0 deletions recipes/mavsdk/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES CXX)

find_package(MAVSDK REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE MAVSDK::mavsdk)
25 changes: 25 additions & 0 deletions recipes/mavsdk/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMake
import os


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeDeps", "CMakeToolchain"

def layout(self):
cmake_layout(self)

def requirements(self):
self.requires(self.tested_reference_str)

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
5 changes: 5 additions & 0 deletions recipes/mavsdk/all/test_package/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
versions:
"1.2.0":
folder: all
"1.1.0":
folder: all
10 changes: 10 additions & 0 deletions recipes/mavsdk/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <mavsdk/mavsdk.h>
#include <iostream>

using namespace mavsdk;

int main()
{
Mavsdk mavsdk{Mavsdk::Configuration{1, 180, false}};
std::cout << "MAVSDK version: " << mavsdk.version() << std::endl;
}
3 changes: 3 additions & 0 deletions recipes/mavsdk/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
versions:
"2.13.0":
folder: all