It is not a good idea to use command-line arguments directly. In case you start your compile with different arguments in different occasions, you may end up compiling different object files with different arguments and things get badly broken. Some months later, you'll change one source file and by mistake compile with different options. That object will now differ and it may not break the build. A decent project will use automatic dependancies, so in case a header file changes, then all objects which included that, will be re-compiled on next invocation of make. (see automatic depencency generation and dependency files (.d)). In case the config gets written to files, the dependency system of make can re-build everything that uses those files in case the files change.
It is a good practice to have configuration file. In case you really do not want to edit those files yourself, you may a) either generate that file dynamically with your makefile b) have a configure-like script, that performs configuration or c) have a bunch of pre-defined configuration files and make rules, that just copy that config to the to-be-used config file.
a) generate config file(s) dynamically: for exmple linux kernel. You may have simpler or more complex config sytem, the easiest way would just have separate make targets, that modify the config. You can have command line arguments that change some fields in those config files. It's a bit tricy to automate editing files, "sed" is your friend there. C projects will include the config file and no problems. If you need to configure make options, generate sub-makefiles and include them. By proper dependencies, if a setting is changed, the required objects and binaries will be re-built and it's bulletproof. Make can take variables from command line, so you may for example implement "make reconfigure F_CPU=8000000".
b) sometimes, it is easier to write a shell script. Do the same as a), just in shell script. The outputs of the script are header file(s) and/or sub-makefiles. Like the configure scripts are implemented, for example "./configure board=board1 f_cpu=8000000" etc.
c) for example, u-boot or linux kernel. You can have pre-defined config files, ie config/board1-config.h. Executing "make board1-config" will just copy the corresponding config file to /config.h. The project will use the toplevel config.h. All re-compiles will work.