Unfortunately, due to Windows linkage, it really does need to be per-project.
When you build a library on Windows, all symbols are private (meaning nothing can call them). For each symbol that you want public and callable by the outside world, you need to mark them with
dllexport during compile time of the library. When you want a downstream consumer to use them, you need to mark them with
dllimport during compile time of the downstream consumer. So far, this is all pretty clear from the macros.
The trouble comes when you want library A to depend on library B. In that case, you need to mark the symbols of library B as
dllimport (so library A can call them), but you need to mark the public symbols of library A as
dllexport. So you can’t just have one set of macros to accomplish this. This is why there are per-project macros.
We’ve traditionally shied away from using
GenerateExportHeader because it locks you into using CMake as your build system, while separate visibility macros don’t. I honestly don’t know if there is substantial interest in building ROS packages without CMake, so I can’t comment on whether that is a good enough reason or not. (There’s also my personal bias that
GenerateExportHeader is “magic”, while the hand-coded macros are straightforward to read, but I can get over that).