1

I have two source files, main.cc, foo.cc.

#include <iostream>

using namespace std;

int main() {

    cout << "main\n";
}

foo.cc

#include <iostream>

using namespace std;

class foo {
public:
    foo() {
        cout << "foo ctor\n";
    }
};

static foo foo_obj;

When I manually compile like this:

$ g++ -c foo.cc -o libfoo.a

$ g++ main.cc libfoo.a -o main

$ ./main

foo ctor

main

But when I use cmake, it won't print foo ctor. Here's the CMakeLists.txt:

cmake_minimum_required(VERSION 3.2)

set(CMAKE_CXX_FLAGS "-std=c++11")

add_library(foo STATIC foo.cc)

add_executable(main main.cc)
target_link_libraries(main foo)

Obviously cmake has done something that I don't expect.

Lewis Chan
  • 695
  • 6
  • 18
  • 1
    @πάντα ῥεῖ It's not the same question, I think. I'm not asking the initialization order across TU. My question is related to some cmake issue, comparing my manual operation's result. – Lewis Chan Sep 03 '19 at 07:18
  • 1
    It doesn't matter that its not the same question but you'll find the answer there. There's no guarantee that `std::cout` will be initialized before `foo_obj`. Nothing to do with CMake BTW. – πάντα ῥεῖ Sep 03 '19 at 07:20
  • 1
    @πάνταῥεῖ - `cout` is initialized by a schwartz counter. It's not subject to the SIOF. – StoryTeller - Unslander Monica Sep 03 '19 at 07:21
  • 2
    @Lewis - You are gonna have to examine the makefiles that Cmake generated. No other way to debug it. – StoryTeller - Unslander Monica Sep 03 '19 at 07:25
  • 2
    It turns out that cmake generate libfoo.a by `ar qc libfoo.a foo.cc`, which results in above situation. @StoryTeller @πάνταῥεῖ Thanks. – Lewis Chan Sep 03 '19 at 07:34
  • @LewisChan I decided to reopen. Feel free to describe the situation and answer your question. – πάντα ῥεῖ Sep 03 '19 at 07:39
  • `foo.cc` is not linked here, see https://stackoverflow.com/questions/56628469/is-lto-allowed-to-remove-unused-global-object-if-there-is-code-in-a-different-tr/56628645#56628645 – user7860670 Sep 03 '19 at 07:48
  • 2
    Command line `g++ -c foo.cc -o libfoo.a` doesn't create a *static library*. Resulted file is just an **object** one, so its better to name it as `foo.o`. But with command `add_library` CMake actually creates a **static library** using `ar` command. (With full command `ar qc libfoo.a foo.o`, not with `foo.cc` as you note in the comment). – Tsyvarev Sep 03 '19 at 07:54
  • @Tsyvarev Oooh, you're right. I didn't realize that... – Lewis Chan Sep 03 '19 at 07:57

1 Answers1

3

It turns out that -Wl,--whole-archive can be used to avoid this. For example write this:

target_link_libraries(main 
  "-Wl,--whole-archive"
  foo
  "-Wl,--no-whole-archive"
)
Lewis Chan
  • 695
  • 6
  • 18