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

[BUILD] Fix build for esp32 #3155

Merged
merged 6 commits into from
Nov 24, 2024

Conversation

albkharisov
Copy link
Contributor

@albkharisov albkharisov commented Nov 20, 2024

Fix for toolchains that alias int32_t to long int. In this way we don't have int in variant of attributes.
If it's defined as strict int32_t, int64_t etc, I think it's better to have strict types everywhere.
ESP-IDF (v5.3.1) toolchain fails to compile as they don't have int in attributes variant list.

Fixes # (issue)

Changes

Please provide a brief description of the changes here.

For significant contributions please make sure you have completed the following items:

  • CHANGELOG.md updated for non-trivial changes
  • Unit tests have been added
  • Changes in public API reviewed

Fix for toolchains that alias int32_t as long int and
in this way confuse all the honest people.
@albkharisov albkharisov requested a review from a team as a code owner November 20, 2024 17:12
Copy link

linux-foundation-easycla bot commented Nov 20, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

Copy link

netlify bot commented Nov 20, 2024

Deploy Preview for opentelemetry-cpp-api-docs canceled.

Name Link
🔨 Latest commit 75eb177
🔍 Latest deploy log https://app.netlify.com/sites/opentelemetry-cpp-api-docs/deploys/674388a817e7a60008130b3b

Copy link
Member

@marcalff marcalff left a comment

Choose a reason for hiding this comment

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

Approved the workflow to run CI, but blocking the merge.

I would like first to understand the issue in more details,
to decide the best course of action for the fix.

@albkharisov
Copy link
Contributor Author

@marcalff
Okay, here are the details:

I've integrated the opentelemetry-cpp library for ESP32 project. In the middle of this process main difficulty was to make it buildable on ESP-IDF (v5.3.1) toolchain.
ESP-IDF compiler is: xtensa-esp-elf-g++ (crosstool-NG esp-13.2.0_20240530) 13.2.0

Repo was configured as follows:

cmake -B build \
    -DCMAKE_TOOLCHAIN_FILE=/opt/esp-idf2/tools/cmake/toolchain-esp32s3.cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_POSITION_INDEPENDENT_CODE=FALSE \
    -DWITH_ZIPKIN=OFF \
    -DBUILD_TESTING=OFF \
    -DWITH_OTLP_GRPC=OFF \
    -DWITH_OTLP_HTTP=OFF \
    -DBUILD_SHARED_LIBS=OFF \
    -DCMAKE_INSTALL_PREFIX=./build/optl \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
    -DWITH_EXAMPLES=OFF \
    -DCMAKE_SYSTEM_PROCESSOR=riscv

CMAKE_SYSTEM_PROCESSOR is here only to pass cmake configure checks, it doesn't affect the OT project. I suppose we have to add here 'xtensa' too.
Toolchain file is common:

include($ENV{IDF_PATH}/tools/cmake/utilities.cmake)

set(CMAKE_SYSTEM_NAME Generic)

set(CMAKE_C_COMPILER xtensa-esp32s3-elf-gcc)
set(CMAKE_CXX_COMPILER xtensa-esp32s3-elf-g++)
set(CMAKE_ASM_COMPILER xtensa-esp32s3-elf-gcc)
set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32s3-elf-)

remove_duplicated_flags("-mlongcalls \
                         -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \
                         -fno-builtin-stpcpy -fno-builtin-strncpy \
                         ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS)
set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE)
remove_duplicated_flags("-mlongcalls \
                         -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \
                         -fno-builtin-stpcpy -fno-builtin-strncpy \
                         ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE)
remove_duplicated_flags("-mlongcalls ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS)
set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE)

Result compile command:

/opt/espressif/tools/xtensa-esp-elf/esp-13.2.0_20240530/xtensa-esp-elf/bin/xtensa-esp32s3-elf-g++ \
    -DOPENTELEMETRY_ABI_VERSION_NO=1 \
    -I/home/albert/work/optl/api/include \
    -I/home/albert/work/optl/sdk/include \
    -I/home/albert/work/optl/sdk \
    -I/home/albert/work/optl/ext/include \
    -mlongcalls \
    -fno-builtin-memcpy \
    -fno-builtin-memset \
    -fno-builtin-bzero \
    -fno-builtin-stpcpy \
    -fno-builtin-strncpy \
    -O3 \
    -DNDEBUG \
    -Wno-error=deprecated-declarations \
    -o \
    CMakeFiles/opentelemetry_trace.dir/tracer_context.cc.obj \
    -c \
    /home/albert/work/optl/sdk/src/trace/tracer_context.cc

This code compiles perfect with host compiler (which is GCC 13.2 by the way, and this stressed me a lot how can 2 similar compilers with exact same flags produce different output!).

But with ESP-IDF it produces an error:

In file included from /home/albert/work/optl/sdk/include/opentelemetry/sdk/common/empty_attributes.h:10,
                 from /home/albert/work/optl/sdk/include/opentelemetry/sdk/trace/recordable.h:11,
                 from /home/albert/work/optl/sdk/include/opentelemetry/sdk/trace/multi_recordable.h:10,
                 from /home/albert/work/optl/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h:11,
                 from /home/albert/work/optl/sdk/src/trace/tracer_context.cc:11:
/home/albert/work/optl/api/include/opentelemetry/common/key_value_iterable_view.h: In instantiation of 'bool opentelemetry::v1::common::KeyValueIterableView<T>::ForEachKeyValue(opentelemetry::v1::nostd::function_ref<bool(opentelemetry::v1::nostd::string_view, absl::otel_v1::variant<bool, long int, long long int, long unsigned int, double, const char*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::span<const bool, 4294967295>, opentelemetry::v1::nostd::span<const long int, 4294967295>, opentelemetry::v1::nostd::span<const long long int, 4294967295>, opentelemetry::v1::nostd::span<const long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const double, 4294967295>, opentelemetry::v1::nostd::span<const opentelemetry::v1::nostd::string_view, 4294967295>, long long unsigned int, opentelemetry::v1::nostd::span<const long long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const unsigned char, 4294967295> >)>) const [with T = std::array<std::pair<std::__cxx11::basic_string<char>, int>, 0>]':
/home/albert/work/optl/api/include/opentelemetry/common/key_value_iterable_view.h:64:8:   required from here
/home/albert/work/optl/api/include/opentelemetry/common/key_value_iterable_view.h:71:20: error: no match for call to '(opentelemetry::v1::nostd::function_ref<bool(opentelemetry::v1::nostd::string_view, absl::otel_v1::variant<bool, long int, long long int, long unsigned int, double, const char*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::span<const bool, 4294967295>, opentelemetry::v1::nostd::span<const long int, 4294967295>, opentelemetry::v1::nostd::span<const long long int, 4294967295>, opentelemetry::v1::nostd::span<const long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const double, 4294967295>, opentelemetry::v1::nostd::span<const opentelemetry::v1::nostd::string_view, 4294967295>, long long unsigned int, opentelemetry::v1::nostd::span<const long long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const unsigned char, 4294967295> >)>) (const std::__cxx11::basic_string<char>&, const int&)'
   71 |       if (!callback(iter->first, iter->second))
      |            ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/albert/work/optl/api/include/opentelemetry/common/key_value_iterable.h:7,
                 from /home/albert/work/optl/sdk/include/opentelemetry/sdk/common/attribute_utils.h:15,
                 from /home/albert/work/optl/sdk/include/opentelemetry/sdk/resource/resource.h:8,
                 from /home/albert/work/optl/sdk/src/trace/tracer_context.cc:9:
/home/albert/work/optl/api/include/opentelemetry/nostd/function_ref.h:89:5: note: candidate: 'R opentelemetry::v1::nostd::function_ref<R(Args ...)>::operator()(Args ...) const [with R = bool; Args = {opentelemetry::v1::nostd::string_view, absl::otel_v1::variant<bool, long int, long long int, long unsigned int, double, const char*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::span<const bool, 4294967295>, opentelemetry::v1::nostd::span<const long int, 4294967295>, opentelemetry::v1::nostd::span<const long long int, 4294967295>, opentelemetry::v1::nostd::span<const long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const double, 4294967295>, opentelemetry::v1::nostd::span<const opentelemetry::v1::nostd::string_view, 4294967295>, long long unsigned int, opentelemetry::v1::nostd::span<const long long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const unsigned char, 4294967295> >}]'
   89 |   R operator()(Args... args) const { return invoker_(callable_, std::forward<Args>(args)...); }
      |     ^~~~~~~~
/home/albert/work/optl/api/include/opentelemetry/nostd/function_ref.h:89:20: note:   no known conversion for argument 2 from 'const int' to 'absl::otel_v1::variant<bool, long int, long long int, long unsigned int, double, const char*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::span<const bool, 4294967295>, opentelemetry::v1::nostd::span<const long int, 4294967295>, opentelemetry::v1::nostd::span<const long long int, 4294967295>, opentelemetry::v1::nostd::span<const long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const double, 4294967295>, opentelemetry::v1::nostd::span<const opentelemetry::v1::nostd::string_view, 4294967295>, long long unsigned int, opentelemetry::v1::nostd::span<const long long unsigned int, 4294967295>, opentelemetry::v1::nostd::span<const unsigned char, 4294967295> >'
   89 |   R operator()(Args... args) const { return invoker_(callable_, std::forward<Args>(args)...); }
      |                ~~~~^~~~~~~~

The cause of this error is that here you have

static const
opentelemetry::common::KeyValueIterableView<
      std::array<std::pair<std::string, int>, 0>>
      kEmptyAttributes(array);

and int here is crucial.

The thing is that here we have a set of allowed values for Attribute:

using AttributeValue =
    nostd::variant<bool,
                   int32_t,
                   int64_t,
                   uint32_t,
                   double,
                   const char *,
                   nostd::string_view,
                   nostd::span<const bool>,
                   nostd::span<const int32_t>,
                   nostd::span<const int64_t>,
                   nostd::span<const uint32_t>,
                   nostd::span<const double>,
                   nostd::span<const nostd::string_view>,
                   // Not currently supported by the specification, but reserved for future use.
                   // Added to provide support for all primitive C++ types.
                   uint64_t,
                   // Not currently supported by the specification, but reserved for future use.
                   // Added to provide support for all primitive C++ types.
                   nostd::span<const uint64_t>,
                   // Not currently supported by the specification, but reserved for future use.
                   // See https://github.com/open-telemetry/opentelemetry-specification/issues/780
                   nostd::span<const uint8_t>>;

And it appeals to int32_t.
If we do g++ -E -P we can see the difference in 2 compilers (host and ESP-IDF):
image

And it results in failing detection int resolution for variant in AttributeValue.

I think the best solution is to change all random non-defined int/long int/long long int values to strict sized types. And I'm saying this not because I'm related to embedded field, but because you specified strict types for AttributeValue, and specifying non-strict in other part seems inconsistent.

Possible side-effects:
I don't think it could lead to something unspecified because int on PC-systems is unlikely be different from int32_t, but on embedded systems it would be better to specify exact type int32_t as it could lead to more predictability.
The worst what can happen: projects compiled on toolchains with int == int64 could have some side-effects.

P.S.
It's not the last PR for bringing up OT on ESP32. This will only fix compile problems. I also have 2 suggestions about:

  • possibility to specify NO_OS value for CMake, because there's no AtFork in pthread realization for ESP32, so fork_unix.cc is not suitable.
  • there is a slight typo in cmake.in: if (OR val OR val)

P.P.S.
I also want to add packages for ESP registry to have easy and seamless integration OT into ESP32 projects.

@albkharisov
Copy link
Contributor Author

I don't know how to put this to already created PR, but this can fix this abandoned issue #2483

@marcalff
Copy link
Member

Thanks for all the details, looking.

@marcalff
Copy link
Member

@albkharisov

Could you clarify, what is the value of sizeof(int) for this platform, and what does INT_MAX looks like in header files (limits.h) ?

short int is 16 bits, long int is 32, long long int is 64, according to the screen shot.

@marcalff
Copy link
Member

P.S. It's not the last PR for bringing up OT on ESP32. This will only fix compile problems. I also have 2 suggestions about:

* possibility to specify NO_OS value for CMake, because there's no AtFork in pthread realization for ESP32, so [fork_unix.cc](https://github.com/open-telemetry/opentelemetry-cpp/blob/main/sdk/src/common/platform/fork_unix.cc#L16) is not suitable.

Ok, let's see this in a different PR.

* there is a slight [typo in cmake.in](https://github.com/open-telemetry/opentelemetry-cpp/blob/main/cmake/opentelemetry-cpp-config.cmake.in#L108): if (OR val OR val)

Thanks for reporting it.
Addressed in #3165

P.P.S. I also want to add packages for ESP registry to have easy and seamless integration OT into ESP32 projects.

Great, thanks for that.

@albkharisov
Copy link
Contributor Author

@albkharisov

Could you clarify, what is the value of sizeof(int) for this platform, and what does INT_MAX looks like in header files (limits.h) ?

short int is 16 bits, long int is 32, long long int is 64, according to the screen shot.

@marcalff

I (502) Test: sizeof(short int) : 2
I (503) Test: sizeof(int) : 4
I (503) Test: sizeof(long int) : 4
I (503) Test: sizeof(long long int) : 8
I (504) Test: INT_MAX : 2147483647
I (504) Test: INT_MIN : 2147483648
I (504) Test: UINT_MAX : 4294967295

It's 4 bytes, but it doesn't help since it doesn't have an alias for int32_t, so for ESP-IDF g++ this std::variant looks like set of (long int, long long int, ...), without int.

@albkharisov
Copy link
Contributor Author

albkharisov commented Nov 24, 2024

It fails to compile test with this.
Error is here: span_data_test.cc

@marcalff
What's best fix?

  • Fix test
  • Revert my last commit

UPD:
fixed test

@marcalff
Copy link
Member

It fails to compile test with this. Error is here: span_data_test.cc

Yes, saw that.

This exposed a different issue: the existing header files are not so clean when it comes to overload resolution, with helpers conflicting with override methods using default values.

@marcalff What's best fix?

* Fix test

* Revert my last commit

UPD: fixed test

Changing the test is only a work around, because the original test code is supposed to work.

I am reverting the change back to your original patch, as it is good enough.

The various overrides need some cleanup, but I prefer to address that in a separate PR, and not delay this one because of unrelated issues.

Copy link

codecov bot commented Nov 24, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 87.86%. Comparing base (c1ef416) to head (75eb177).
Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #3155   +/-   ##
=======================================
  Coverage   87.86%   87.86%           
=======================================
  Files         195      195           
  Lines        6151     6151           
=======================================
  Hits         5404     5404           
  Misses        747      747           
Files with missing lines Coverage Δ
...nclude/opentelemetry/sdk/common/empty_attributes.h 100.00% <ø> (ø)
sdk/include/opentelemetry/sdk/trace/span_data.h 98.69% <ø> (ø)
---- 🚨 Try these New Features:

Copy link
Member

@marcalff marcalff left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the fix, and all the details for this platform.

@marcalff marcalff merged commit 31956f8 into open-telemetry:main Nov 24, 2024
57 checks passed
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.

2 participants