# Why can't I re-export an imported executable?

**URL:** <https://discourse.cmake.org/t/why-cant-i-re-export-an-imported-executable/3489>\
**Category:** Code\
**Created:** [June 3, 2021, 10:27pm UTC](https://discourse.cmake.org/t/why-cant-i-re-export-an-imported-executable/3489 "2021-06-03T22:27:51Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![alex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/alex/32/125_2.png) [@alex](https://discourse.cmake.org/u/alex)\
**Post date:** [June 3, 2021, 10:27pm UTC](https://discourse.cmake.org/t/why-cant-i-re-export-an-imported-executable/3489/1 "2021-06-03T22:27:51Z")

</div>

I want to make Halide’s build support cross-compilation.

- Host Halide depends on:
  - Host LLVM libraries
  - Host LLVM tools: `llvm-as` and `clang`

- Target Halide depends on:
  - Host Halide tools
  - Host LLVM tools: `llvm-as` and `clang`
  - Target LLVM libraries

To pass the host Halide tools to target Halide, there’s a simple solution:

1. Organize Halide’s tools into a directory that `export()`s them into a package called HalideHost.
2. In the parent directory, check if `CMAKE_CROSSCOMPILING` is set.
  1. If so, `find_package(HalideHost)`
  2. Otherwise, `add_subdirectory(tools)`.

3. Set `HalideHost_ROOT` to the host build directory in the target configure command line.

On the other hand, getting _both_ LLVM host tools _and_ LLVM target libraries is challenging. Calling `find_package(LLVM)` will always return either one or the other.

**My desired solution** was to `export()` the host LLVM tools under the `HalideHost::` namespace and use aliases in the host build for consistency. Unfortunately, `export()` reports a bogus error that it can’t determine the linker language for the imported executable. Setting `IMPORTED_LINK_INTERFACE_LANGUAGES` to `CXX` does not resolve this.

**My workaround** is to use `file(GENERATE)` to do what I expected `export()` to do:

```cmake
file(GENERATE
     OUTPUT "${CMAKE_BINARY_DIR}/share/HalideHost/HalideHostConfig.cmake"
     CONTENT [[
include(${CMAKE_CURRENT_LIST_DIR}/HalideHost-exports.cmake)

add_executable(HalideHost::llvm-as IMPORTED)
set_target_properties(
  HalideHost::llvm-as
  PROPERTIES
  IMPORTED_LOCATION "$<TARGET_FILE:llvm-as>"
)
]])

```

Why can’t `export()` do this, and why would it need to know the linker language for an imported executable?

Moreover, is this a good solution? If not, what should I do instead?

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [June 7, 2021, 8:28pm UTC](https://discourse.cmake.org/t/why-cant-i-re-export-an-imported-executable/3489/2 "2021-06-07T20:28:25Z")

</div>

VTK has a similar problem. The codebase has an alternate “mode” where it compiles just the tools needed for cross-compilation and exports them under a new namespace (`VTKCompileTools::`). Everything that uses them first looks for these names and only then falls back to the `VTK::` name for them. This allows the selection to be made at the top-level.

As for exporting other project’s targets, I think I would recommend instead just making your own `INTERFACE` targets which do this (though `add_executable(INTERFACE)` isn’t really a thing today, so is of little consolation with existing CMake releases). It is basically [this issue](https://gitlab.kitware.com/cmake/cmake/-/issues/18711) except that it was compiled (elsewhere).

---

<div class="post-metadata">

**Author:** ![alex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/alex/32/125_2.png) [@alex](https://discourse.cmake.org/u/alex)\
**Post date:** [June 8, 2021, 3:46am UTC](https://discourse.cmake.org/t/why-cant-i-re-export-an-imported-executable/3489/3 "2021-06-08T03:46:16Z")

</div>

> [@ben.boeckel](#):
>
> As for exporting other project’s targets, I think I would recommend instead just making your own `INTERFACE` targets which do this

Yeah, so it’s only executables that I want to do this with. So I think that my solution here is fine, especially given the fact that both the host and target LLVMs must be the same version (`llvm-as` and `clang -emit-llvm` are not compatible across major versions, anyway).
