CreateProcess is complex because spawning a new process is essentially complex.
The brilliance of fork/exec is in the realization that the tasks you do during process creation are the same as the tasks you do during normal execution, and therefore you can just re-use those functions. For example, CreateProcess has a parameter for the current directory; fork/exec doesn't need one because you just use chdir on the child side of fork.
The proliferation of exec* is indeed baffling, but these are just dumb variants trying to make the exec call itself "easier." They don't reflect any essential complexity.
The brilliance of fork/exec is in the realization that the tasks you do during process creation are the same as the tasks you do during normal execution, and therefore you can just re-use those functions. For example, CreateProcess has a parameter for the current directory; fork/exec doesn't need one because you just use chdir on the child side of fork.
The proliferation of exec* is indeed baffling, but these are just dumb variants trying to make the exec call itself "easier." They don't reflect any essential complexity.