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

Cross compiling fixes and improvements #59

Merged
merged 6 commits into from
Nov 26, 2020

Conversation

eigendude
Copy link
Contributor

@eigendude eigendude commented Mar 7, 2020

Description

This PR contains a set of fixes and improvements to the build system to allow for cross-compiling, and then applies several code fixes needed for newer GCC versions.

Structure of the PR

The PR is organized as follows:

  1. Improvements needed for cross-compiling
  2. Build fixes

Improvements for cross-compiling

Commits:

These changes enable more control over the build process when embedding in another build system.

CMake is controlled by user variables; the first one we need is -DHUNTER_ENABLED=OFF so that we can have control over dependencies.

Another useful variable is -DTESTING=OFF, because embedding test infra drastically increases the up-front effort. The first commit above allows this variable to exclude test infra from the dependency discovery in addition to the build.

Finally, I added two variables to allow the build system to provide the protobuf compiler and headers:

  • -DProtobuf_PROTOC_EXECUTABLE=$(NATIVEPREFIX)/bin/protoc
  • -DProtobuf_INCLUDE_DIR=$(PREFIX)/include

We might also want to disable -Werror for examples, but I haven't done that here.

Build fixes

Commits:

These fixes should be evident by visual inspection. Error log included in the commit messages.

How has this been tested?

With these changes in place, I'm able to compile and link libp2p and dependencies using two build systems: OpenEmbedded, and Kodi's depends system.

Here's my work on these two build systems. Commits are structured so that libp2p inclusion can be upstreamed.

Additions for OpenEmbedded (meta-cryptocurrency layer)

Commits:

This commit enables libp2p support in the OpenEmbedded ecosystem.

Additions for Kodi

Commits for C++17 support:

Kodi currently uses C++14. These 3 commits can be PR'd to enable C++17 support, needed for libp2p and filecoin. Merging is probably a long way off, as Kodi supports a long tail of devices with embedded build systems that often use old compilers.

Commits for the depends build system:

With the commits in this PR, I was able to cross-compile libp2p for x86_64 Linux and macOS for runtime testing. Next is to test compilation for Raspberry Pi and Android NDK.

Commits for runtime testing:

I didn't spend a lot of time on kademlia, but echo and gossip test code produces promising output. Tested on Linux x86_64 and macOS.

Benefits

IoT is the obvious goal, but Kodi opens up another little-known area of embedded: OTT (over-the-top), stretching across both set-top boxes and almost all mobile

Related PRs

This PR is needed for filecoin-project/cpp-filecoin#114.

Copy link
Member

@igor-egorov igor-egorov left a comment

Choose a reason for hiding this comment

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

Many thanks for your contribution!

The only change I request - we have to decide what to do with commented out lines in cmake/functions.cmake

@@ -45,8 +45,8 @@ function(add_flag flag)
endfunction()

function(compile_proto_to_cpp PROTO_LIBRARY_NAME PB_H PB_CC PROTO)
get_target_property(Protobuf_INCLUDE_DIR protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc IMPORTED_LOCATION_RELEASE)
#get_target_property(Protobuf_INCLUDE_DIR protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
Copy link
Member

Choose a reason for hiding this comment

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

Our rule of thumb is that the commented code has to be either uncommented or removed.

Please check this. Probably the commented lines could be conditionally enabled (for example, depending on some configuration variable).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I don't intend to leave commented code - commit is marked [WIP]. They should probably be conditionally enabled, but on what condition? They broke my cross compile attempt, so maybe we switch on cross compiling? I don't think we should expose a CMake option.

Do you know why these lines were added in the first place?

Copy link
Member

Choose a reason for hiding this comment

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

What I see here - in these two lines we are reading INTERFACE_INCLUDE_DIRECTORIES and IMPORTED_LOCATION_RELEASE parameters, which have to be set by find_package(Protobuf ...) command.

The error from the commit message says - it was not succeeded to find a proto compiler in your environment. Probably you can additionally specify own custom CMake toolchain file which will set_target_property(...). Otherwise, it looks like proto couldn't be compiled without a compiler :)

We could employ CMAKE_CROSSCOMPILING var:

if (NOT CMAKE_CROSSCOMPILING)
  get_target_property(Protobuf_INCLUDE_DIR protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
  get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc IMPORTED_LOCATION_RELEASE)
endif()

BUT, the variables still have to be defined in another way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tackled this the following way:

namespace libp2p::common {
libp2p::common::Hash256 operator""_hash256(const char *c, size_t s) {
libp2p::common::Hash256 hash{};
std::copy_n(c, std::min(s, 32ul), hash.rbegin());
std::copy_n(c, std::min(s, static_cast<size_t>(32ul)), hash.rbegin());
Copy link
Member

Choose a reason for hiding this comment

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

just a minor note.
It looks like l type specifier for constants can be omitted due to explicit static_cast.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I drop the u type specifier too?

Copy link
Member

Choose a reason for hiding this comment

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

u could still be kept as an indicator of the value's "nature".
That is not an issue at all. We may leave it as is even with l.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the l and left the u. this leaves the indicator of its "nature", and de-duplicates the notion of its "size".

Copy link
Contributor

Choose a reason for hiding this comment

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

imho, casting to the same type explicitly looks more clear.

@@ -10,6 +10,9 @@
#include <libp2p/protocol/gossip/impl/connectivity.hpp>
#include <libp2p/protocol/gossip/impl/message_builder.hpp>

#define SPDLOG_TRACE_ON
Copy link
Member

Choose a reason for hiding this comment

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

The fact you had to define the macro is looking suspicious fry

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure if needed, or resulted from grasping at straws...

spd was a headache and I had to comment random log lines just to get libp2p to link. I'll put some more time into this.

Copy link
Member

Choose a reason for hiding this comment

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

Please check if it works when the macro is not defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I dropped the commit entirely.

@igor-egorov igor-egorov requested a review from masterjedy March 12, 2020 12:14
@igor-egorov
Copy link
Member

An update: it seems illegal to remove CONFIG from find_package commands :(

@eigendude
Copy link
Contributor Author

Hm, CONFIG requires a cmake config file, but it seems this is provided by hunter, whereas cmake natively provides a find module. how would we find packages without hunter?

@eigendude
Copy link
Contributor Author

I think I figured it out. I'm re-approaching without removing CONFIG.

@eigendude
Copy link
Contributor Author

eigendude commented Mar 18, 2020

I've updated the PR. All CONFIG changes were dropped. Instead, I updated my build system to use the hunterized repos. The down side is that these don't seem to be fully up to date.

I tested cross compiling to Android NDK with clang. Only change needed was a compiler warning fix, which I've added.

@eigendude
Copy link
Contributor Author

Any word? I compiled libp2p into an NDK app (kodi) and ran echo and kademlia examples successfully on Android.

@masterjedy
Copy link
Contributor

Any word? I compiled libp2p into an NDK app (kodi) and ran echo and kademlia examples successfully on Android.

sounds great

This change shuffles the order of several CMake steps to expose CMake
options to included files.

By defining options before inclusion, included files are able to access
the input provided by the build system.
When building without Hunter, it is desirable to pass the path to protoc and
the protobuf include directory from the build system. Allow these variables
to be overridden.

Fixes the error:

| CMake Error at cmake/functions.cmake:52 (message):
|   Protobuf_PROTOC_EXECUTABLE is empty
| Call Stack (most recent call first):
|   cmake/functions.cmake:96 (compile_proto_to_cpp)
|   src/crypto/protobuf/CMakeLists.txt:6 (add_proto_library)
Error was:

| literals.cpp: In function 'libp2p::common::Hash256 libp2p::common::operator""_hash256(const char*, size_t)':
| literals.cpp:17:36: error: no matching function for call to 'min(size_t&, long unsigned int)'
|    17 |     std::copy_n(c, std::min(s, 32ul), hash.rbegin());
|       |                                    ^
Error was:

| literals.cpp: In function 'libp2p::common::Hash256 libp2p::common::operator""_hash256(const char*, size_t)':
| literals.cpp:19:36: error: no matching function for call to 'min(size_t&, long unsigned int)'
|    19 |     std::copy_n(c, std::min(s, 32ul), hash.rbegin());
|       |                                    ^
When compiling with -Werror, this causes the build to fail.

Warning was:

| yamux_frame.cpp:103:28: error: comparison of integers of different signs: 'gsl::span::index_type' (aka 'int') and 'const uint32_t' (aka 'const unsigned int') [-Werror,-Wsign-compare]
|     if (frame_bytes.size() < YamuxFrame::kHeaderLength) {
|         ~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
@igor-egorov
Copy link
Member

wow, this pr is still alive :) queued for check

@eigendude
Copy link
Contributor Author

yup, the PR lives. I started a new project, embedded Interplanetary Identifiers, to see if an identity solution could solve the problem I'm working on. In the course of implementing IPIDs I rebased this PR and run-time tested it again.

@kamilsa kamilsa merged commit 0ba4a26 into libp2p:master Nov 26, 2020
@eigendude eigendude deleted the cross-compile branch November 30, 2020 22:58
@FlorianFranzen
Copy link
Contributor

FlorianFranzen commented Mar 29, 2021

@eigendude; Thank you for this contribution. I opened a PR in qdrvm/kagome#703 to apply the relevant patches to kagome as well.

@eigendude
Copy link
Contributor Author

@FlorianFranzen thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants