Hmm... actually you don't specify an executable name per project, but per target.
I find the way Code::Blocks handles things a lot easier than for example how Visual Studio does (I assume you did not mean to compare to Dev-CPP or Relo which are rather poor at handling projects).
On a large project, you would have one workspace and 20 project files using Visual Studio. One project file for every library, part, or executable that you want to build, with optional inter-project dependencies.
Code::Blocks uses one project file for everything and just defines one target for every component, this is a lot simpler and easier to follow. All dependencies are in one file, too.
You can very well work like this to get to your debug/release builds:
A
workspace is just a convenient collection of projects.
A
project holds together everything that makes "one product" or "one product suite". Change the optimization/debug flags here, all targets will inherit them (unless they explicitely override them). This is for example important if you use "dangerous" tuning parameters like
regparm which generate non-ABI compatible code. With the VS approach, your code would crash and burn.
A
target defines every "entity" which may be built separately. This may be a shared library, a static library, a plugin, a tool, or two different versions of the main program (a full version and crippleware version, for example).
It is different from how MS does it, true, but is it worse? A matter of taste I'd say