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

CMake Interprocedural Optimization (LTO) with static libraries uses the wrong tools #11143

Closed
PJK136 opened this issue May 13, 2020 · 7 comments

Comments

@PJK136
Copy link
Contributor

PJK136 commented May 13, 2020

Since recent the CMake cleanup (#10934), CMake uses the system llvm-ar instead of emar when creating a static library because CMake doesn't seem to honor CMAKE_AR when CMAKE_INTERPROCEDURAL_OPTIMIZATION is set to TRUE. Instead, it uses CMAKE_C_COMPILER_AR or CMAKE_CXX_COMPILER_AR defined by CMake compilator modules.

Example (tested on Ubuntu 19.10 and Arch Linux)

CMakeLists.txt :

project(test)
cmake_minimum_required(VERSION 3.12)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
add_library(lib STATIC lib.cpp)

lib.cpp is an empty file.

  • If llvm is installed on the system, CMakeCache.txt contains :
//LLVM archiver
CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/llvm-ar

//Generate index for LLVM archive
CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/llvm-ranlib

and the compilation finishes without error but if we run emmake make VERBOSE=1, we can see that it uses the system llvm-ar and llvm-ranlib.

  • If llvm is not installed, CMakeCache.txt contains :
//LLVM archiver
CMAKE_CXX_COMPILER_AR:FILEPATH=CMAKE_CXX_COMPILER_AR-NOTFOUND

//Generate index for LLVM archive
CMAKE_CXX_COMPILER_RANLIB:FILEPATH=CMAKE_CXX_COMPILER_RANLIB-NOTFOUND

and there is an error when linking liblib.a.
emmake make VERBOSE=1 tells us :

"CMAKE_CXX_COMPILER_AR-NOTFOUND" cr liblib.a  CMakeFiles/lib.dir/lib.cpp.o
Error running link command: No such file or directory

Suggestion

One of these should work :

  set(CMAKE_C_CREATE_STATIC_LIBRARY "<CMAKE_AR> rc <TARGET> <LINK_FLAGS> <OBJECTS>")
  set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_AR> rc <TARGET> <LINK_FLAGS> <OBJECTS>")

The linking command become : "[some_path]/emsdk/upstream/emscripten/emar" rc liblib.a @CMakeFiles/lib.dir/objects1.rsp for both non-IPO and IPO build.

  • Add these lines to cmake/Modules/Platform/Emscripten.cmake (somewhere after CMAKE_AR and CMAKE_RANLIB definitions) :
set(CMAKE_C_COMPILER_AR "${CMAKE_AR}")
set(CMAKE_CXX_COMPILER_AR "${CMAKE_AR}")
set(CMAKE_C_COMPILER_RANLIB "${CMAKE_RANLIB}")
set(CMAKE_CXX_COMPILER_RANLIB "${CMAKE_RANLIB}")

The linking commands become :

"[some_path]/emsdk/upstream/emscripten/emar" cr liblib.a  CMakeFiles/lib.dir/lib.cpp.o
"[some_path]/emsdk/upstream/emscripten/emranlib" liblib.a

for both non-IPO and IPO build.

I think the second solution is better because without IPO, CMake runs both ar and ranlib and this solution tells CMake to specifically use emscripten's ar and ranlib tool for any purpose and not only static linking. (I don't really have knowledge in the linking process so maybe just ar only is better in this case, feel free to correct me if I'm wrong.)

@sbc100
Copy link
Collaborator

sbc100 commented May 13, 2020

Seems like the second solution is the more correct one. Do you fancy sending a PR?

@PJK136
Copy link
Contributor Author

PJK136 commented May 14, 2020

There you go #11161.

@Xeverous
Copy link

Xeverous commented Jan 3, 2021

Is this issue still relevant? PR is merged but the issue remains open. I can not currently test it due to regression mentioned in #13067.

@PJK136
Copy link
Contributor Author

PJK136 commented Jan 3, 2021

The merged PR fixed the issue and I can say that it still works since then up to 2.0.8 (I didn't test later versions). So this issue could be closed long ago. 👍

@PJK136 PJK136 closed this as completed Jan 3, 2021
@Xeverous
Copy link

Xeverous commented Jan 3, 2021

Strange, it doesn't work for me. I can not build static libraries with LTO. I get CMAKE_CXX_COMPILER_AR-NOTFOUND invokation, even on 2.0.8. I'm using CMake 3.18.2

@PJK136
Copy link
Contributor Author

PJK136 commented Jan 3, 2021

I just tried with Arch Linux, CMake 3.19.2 and emscripten 2.0.8 with the following project:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.12)
project(emscripten-static-lib-ipo)

include(CheckIPOSupported)
check_ipo_supported()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)

add_library(mylib STATIC mylib.cpp)

mylib.cpp:

int f() {
    return 0;
}

In the source dir :

mkdir build && cd build
emcmake cmake ..
emmake make

Does this work for you?
If not, can you try emmake make VERBOSE=1 ?

Edit: read too fast sorry. So your AR doesn't seem to be detected, strange...

@Xeverous
Copy link

Xeverous commented Jan 3, 2021

Added an executable to your example, but still it builds correctly. My project does not - perhaps this example is not complex enough to try to invoke AR program.

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

No branches or pull requests

3 participants