Ways of building the code
Ways of building the code
Hello!
""My way of compiling the C-code of my kernel is that I have a line, which joins all of my C code files into one before "make", in my build-script.
So I don't have to use any #include:s.""
Then it compiles the asm and the C into two object files and links them into ELF.
Is the thing inside the ""tetramarks"" good or bad or between?
""My way of compiling the C-code of my kernel is that I have a line, which joins all of my C code files into one before "make", in my build-script.
So I don't have to use any #include:s.""
Then it compiles the asm and the C into two object files and links them into ELF.
Is the thing inside the ""tetramarks"" good or bad or between?
Re:Ways of building the code
seems like a very silly way to do things especially as the project grows over time.
really the usual way is like this:
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
gcc -c file3.c -o file3.o
and then:
gcc file1.o file2.o file3.o -o program
now, with kernels you are gonna probably way a special linker script in that last step or at the very least some linker options, but the point is this is the norm.
but why you may ask.
well if i have a 20,000 line kernel (mine is about this at the moment). If i modify ONE line of code, i only have to recompile the .c which contained it and then relink. But your example would require a complete recompile of the kernel.
It is a HUGE time saver to modularize the code and minimize how much of it is recompiled when you make changes.
really the usual way is like this:
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
gcc -c file3.c -o file3.o
and then:
gcc file1.o file2.o file3.o -o program
now, with kernels you are gonna probably way a special linker script in that last step or at the very least some linker options, but the point is this is the norm.
but why you may ask.
well if i have a 20,000 line kernel (mine is about this at the moment). If i modify ONE line of code, i only have to recompile the .c which contained it and then relink. But your example would require a complete recompile of the kernel.
It is a HUGE time saver to modularize the code and minimize how much of it is recompiled when you make changes.
Re:Ways of building the code
There is no rule against doing it this way, but header files and #include's are your friend. The idea is to declare a couple of logically related functions and their parameters (plus usually adding some comments as to what they're doing) in a .h header file, and have all the implementation details in the .c "implementation" file.
This is how, like, 99.9% of all software is written.
I think it's funny that 99.9% of the remaining 0.1% seem to be people writing kernel code. You should be quite fluent in software development before you come up with the idea to write your own OS, so that writing headers and using #include's in a smart way should be second nature...
This is how, like, 99.9% of all software is written.
I think it's funny that 99.9% of the remaining 0.1% seem to be people writing kernel code. You should be quite fluent in software development before you come up with the idea to write your own OS, so that writing headers and using #include's in a smart way should be second nature...
Every good solution is obvious once you've found it.
Re:Ways of building the code
Separate compilation also allows to isolate things in each source file , so they don't crowd the namespace. (you can have #defines, "static" helper functions, data, etc. that are not seen outside a source file)
Header files then provide "interfaces" and indicate dependencies between source files.
Of course, you can do that in any case, by wrapping "private" stuff of each source file in a separate namespace (if you can compile it in C++ mode)..
BUT: there's a nice thing (for C++) you can get by including all source files together, which you don't normally get otherwise. (at the cost of full recompile)
with separate compilation of classes, if you use a class whose method bodies are in a different source file, you will have to duplicate method prototypes from the header in the implementation source file with bodies, which is an ugly piece of redundancy.
with all sources getting lumped together, you can just implement methods either in the class body or outside, as you like.
(IMO. I haven't tried this, but I think it should work. I may want to try it sometime.)
Header files then provide "interfaces" and indicate dependencies between source files.
Of course, you can do that in any case, by wrapping "private" stuff of each source file in a separate namespace (if you can compile it in C++ mode)..
BUT: there's a nice thing (for C++) you can get by including all source files together, which you don't normally get otherwise. (at the cost of full recompile)
with separate compilation of classes, if you use a class whose method bodies are in a different source file, you will have to duplicate method prototypes from the header in the implementation source file with bodies, which is an ugly piece of redundancy.
with all sources getting lumped together, you can just implement methods either in the class body or outside, as you like.
(IMO. I haven't tried this, but I think it should work. I may want to try it sometime.)
Re:Ways of building the code
zloba wrote: with separate compilation of classes, if you use a class whose method bodies are in a different source file, you will have to duplicate method prototypes from the header in the implementation source file with bodies, which is an ugly piece of redundancy.
Won't you have the same 'problem' in C too? I never considered this a problem - when you have declaration and implementation in two different places, somehow you'll have to show which method implementation belongs to which declaration, and providing the prototype again is a straight forward method to me...
Well, I don't know your programming style and how well you come along with it, so to everyone his own. (I hope this proverb is valid in english)zloba wrote: with all sources getting lumped together, you can just implement methods either in the class body or outside, as you like.
But IMO you should at least keep consistency among your sources. Meaning that you should either implement everything in the class body (like in Java) or everything outside.
No rant - just comment
cheers Joe
Re:Ways of building the code
2 JoeKayzA:
And it didn't have to be this way in C++. In my language, I can just "implement" a prototype, interface, virtual method, etc. like this:
(<prototype> $imp <body>)
In C++, it could've been smth. like:
<prototype>.implement [ name ] [ (renamed-args) ]{ <body> };
Yes, same 'problem' in C, with function prototypes.Won't you have the same 'problem' in C too?
Straightforward? Yes. Elegant? I'll say no. First, I have to retype (or copy and paste) the prototypes in implementation. Then, prototypes change, and need to be updated in the implementation. Redundancy isn't good.somehow you'll have to show which method implementation belongs to which declaration, and providing the prototype again is a straight forward method to me...
And it didn't have to be this way in C++. In my language, I can just "implement" a prototype, interface, virtual method, etc. like this:
(<prototype> $imp <body>)
In C++, it could've been smth. like:
<prototype>.implement [ name ] [ (renamed-args) ]{ <body> };
That was just a speculation on one _possible_ benefit of the lumping together. _Not_ advocacy of immediately switching to said lumping. I did say that I haven't tried this..Well, I don't know your programming style and how well you come along with it
I agree.But IMO you should at least keep consistency among your sources.
Sounds valid enough to me. (I'm not a native english-speaker)(I hope this proverb is valid in english)
Re:Ways of building the code
To Each his own is the 'real' version, IIRC.so to everyone his own
And it really should be:
To Everyone their own.
Re:Ways of building the code
I consider it pretty likely that people that don't like the default coding style(s) also don't like the default OSes.Solar wrote: This is how, like, 99.9% of all software is written.
I think it's funny that 99.9% of the remaining 0.1% seem to be people writing kernel code.
Re:Ways of building the code
Do they? I mean, do prototypes change? In my experience, new prototypes get added, but existing ones usually don't change, because of the possibility of existing code using the old interface.zloba wrote: ...prototypes change, and need to be updated in the implementation. Redundancy isn't good.
C++ is not a laboratory language. It was designed to be as compatible to C as possible. Of course many things could have been done in a much cleaner way, but would C++ have been as successful if it had been significantly different than C?And it didn't have to be this way in C++. In my language...
Means, no-one can look at the function prototypes at a glance (without using external tools), because they are always mingled together with their implementations...I can just "implement" a prototype, interface, virtual method, etc. like this:
(<prototype> $imp <body>)
Straightforward? Dunno, still used to the C/C++ ways. Elegant? Not more so than the way things are...In C++, it could've been smth. like:
<prototype>.implement [ name ] [ (renamed-args) ]{ <body> };
If you're in Rome, do as the Romans do. C/C++ code traditionally has declarations in seperate header files, apart from their implementation.That was just a speculation on one _possible_ benefit of the lumping together. _Not_ advocacy of immediately switching to said lumping. I did say that I haven't tried this..
Every good solution is obvious once you've found it.
Re:Ways of building the code
Oh, right, sorry. ::)Cjmovie wrote: To Each his own is the 'real' version, IIRC.
And this is actually why I don't like to edit Java sources with a plain text editor. You have to scroll for miles to find a method prototype, and without syntax highlighting, it can get even more stressing. Therefore I prefer 'advanced' source editors for Java (an IDE, admittedly), which at least support collapsing and expanding of code blocks.Means, no-one can look at the function prototypes at a glance (without using external tools), because they are always mingled together with their implementations...
But I believe that C and C++ have different reasons for seperating prototypes in header files than just readability, in the first place it's probably more the 'compile first, then link'-issue. But I think Solar probably has more experience in these things...
cheers Joe
Re:Ways of building the code
Data encapsulation. For one, it's a good programming practice, especially in OO, and I was honestly surprised to learn that Java made such a bad job at it. I frankly don't care how a function is implemented 95% of the time. They basically "outsourced" that job to javadoc...JoeKayzA wrote:
But I believe that C and C++ have different reasons for seperating prototypes in header files than just readability, in the first place it's probably more the 'compile first, then link'-issue. But I think Solar probably has more experience in these things...
Second, consider the times when OSS / GPL wasn't yet the hype it is today, and code quite frequently was shipped without source (gasp!). You'd have some blackbox named libsomething.a or libsomeother.o, containing all the nice functions you need.
Sure, you don't need prototypes to use the functions therein, but it makes for a better error checking. You'd also like to use symbolic constants instead of magic numbers, and there might be some macros of use with that library, too. All that is made available in the header file, without the library vendor disclosing its valuable library innards.
Java does some of this with smart tools (reading the prototypes from bytecode), and doesn't do other things at all (macros, although nothing keeps you from running cpp over Java sources ). Don't forget that C and Java are several generations apart, not only in language design but also in the available hardware power.
Every good solution is obvious once you've found it.
Re:Ways of building the code
I suspect static constant values should substitute macros, they are linked at load time too, just as all the classes and methods. But I already noticed several rants about the lack of a preprocessor, and AFAIK, there are even some inofficial Java preprocessors out there....it's probably all about style and habits. And somehow I get a bad feeling that this will get moved into the 'General Programming' section soon...Solar wrote: Java does some of this with smart tools (reading the prototypes from bytecode), and doesn't do other things at all (macros, although nothing keeps you from running cpp over Java sources ).
cheers Joe
Re:Ways of building the code
If you think of "macros" only as [tt]#define foo 42[/tt]. Macros can be much more (and a great way of obfuscating your source or introducing subtle bugs, too).JoeKayzA wrote: I suspect static constant values should substitute macros, they are linked at load time too, just as all the classes and methods.
I didn't rant. I tend to take a language as-is, and try not to fall for the "you can write FORTRAN in any language" kind of mindset. It's just that Java and C++, while looking pretty similar at first glance, are two completely different approaches to programming....it's probably all about style and habits.
Now there's an idea.And somehow I get a bad feeling that this will get moved into the 'General Programming' section soon...
Every good solution is obvious once you've found it.
Re:Ways of building the code
They very much do. Design changes, arguments change. I agree it doesn't happen too often (usually), but it does.Do they? I mean, do prototypes change?
If the project has been published and in wide use, yes. But how about small projects? Rapid prototypes, pre-release? Internal interfaces? etc. What should I maintain compatibility with?new prototypes get added, but existing ones usually don't change, because of the possibility of existing code using the old interface.
"Change is the only thing that is constant" (c) not sure about source and exact wording.
Where does that break downward compatibility? Sure the new code won't work with plain-C compilers, but neither will methods, namespaces and lots of other things.It was designed to be as compatible to C as possible.
How does that make it significantly different more than, say, type overloading or any other C++ feature? You just can't compile these things in C mode, period. Not without expressing them in terms C can understand.would C++ have been as successful if it had been significantly different than C?
You can copy the prototype anywhere as a comment, for the sake of documentation.Means, no-one can look at the function prototypes at a glance
Or make duplicating a prototype _optional_.
Or allow a stand-alone precondition on the prototype, so you can put it anywhere it if it pleases you. (even in the user code)
This does it for documentation _and_ can be used to raise the red flag when the prototype changes and you forget to update it at a body. (Instead of silently compiling it with the old prototype and then producing an obscure linker error)
Ok, the way C/C++ does it with separate prototypes and bodies accomplishes that (mostly), but only for the bodies, and you get no choice, whether you need this or not.
Are you saying that existing languages are final and no new ones should ever be created?I tend to take a language as-is, and try not to fall for the "you can write FORTRAN in any language" kind of mindset.
I've been taking languages "as-is" for some time now, and I'm fed up with all the little things combined.
FYI, it's not FORTRAN, far from it. Nor a laboratory language. It is intended to replace C/C++ and to be as practical (more so), barring immediate compatibility and general acceptance. How's that for FORTRAN?
I agree, C++ is what it is, generally accepted and all, no one argues. But that doesn't mean I have to stick with it. New OS, new language, new everything.
Re:Ways of building the code
You completely missed the point here, the point is not that C++ code can be built with a C compiler but that C code can be built with a C++ compiler. At the time everything was in C so C++ was designed to allow incremental adaption to C++ features.zloba wrote:How does that make it significantly different more than, say, type overloading or any other C++ feature? You just can't compile these things in C mode, period. Not without expressing them in terms C can understand.would C++ have been as successful if it had been significantly different than C?
You do realise that that is similar to the point of the D language.Are you saying that existing languages are final and no new ones should ever be created?I tend to take a language as-is, and try not to fall for the "you can write FORTRAN in any language" kind of mindset.
I've been taking languages "as-is" for some time now, and I'm fed up with all the little things combined.
FYI, it's not FORTRAN, far from it. Nor a laboratory language. It is intended to replace C/C++ and to be as practical (more so), barring immediate compatibility and general acceptance. How's that for FORTRAN?
I agree, C++ is what it is, generally accepted and all, no one argues. But that doesn't mean I have to stick with it. New OS, new language, new everything.