Option 1 only works if there is a sensible unified interface, and if you feel like spending the time making that for what could be just one line per target. And it just won't work for things that don't really "have an interface", i.e. conditionally adding an __attribute__((optnone)) to a function that a specific compiler version gets stuck in an infinite loop optimizing, or macros that expand to some _Pragma-s that apply to a loop following it for controlling unrolling/vectorization if available, or managing custom inlining configurations for functions based on the optimization/debug levels, or defining a type as either 32-bit or 64-bit depending on requirements, or redefining all printf & fprintf usages to something mingw-friendly.
Many of those could be solved by some other means, but C macros neatly encompass all of those.
I don't think is not a bad idea. You can't solve language incompatibilities in the language it self. Textual macro languages solves this nicely.
CPP is what makes C and C++ work for projects aimed at multiple platforms or compiler vendors.