The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: frktons on September 14, 2010, 04:53:36 PM

Title: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 04:53:36 PM
Somebody in the English speaking countries traslated the Latin saying

Divide et impera

into a similar, but still slightly different:

Divide and conquer.

Now what's the matter of dividing things in order to better manage them?
Here we have an example: big programs, the bigger the more difficult to manage.

I'm not yet at that point with my small ridiculous ASM examples,
but, as time passes, they are becoming bigger nevertheless.

I'm already in the hundreds of instructions. So before reaching the thousands
it'd better start dividing them.  :P

I'd like to ask something about this matter to the more experienced ones, probably
all of you are more experienced ASM programmers than me.

Let's use as an example a recent code, ASCII.ASM, some hundreds lines.
Inside the prog I have more or less a dozen PROCs. If I'd like to expand this prog further,
adding a menu, many more screens, dozens more PROCs, it'll get much bigger
and less manageable.

My question is, what do you usually do to organize your projects?
Do you use static LIBs to include, or DLLs, or you prefer a bounce of
OBJ inside a folder and you link them together with a MAKE file?
Or what else?

Any comments about the method you use, and why, would be much appreciated.

Thanks

Frank

Title: Re: DIVIDE ET IMPERA
Post by: redskull on September 14, 2010, 05:19:28 PM
A properly written MAKE files is your best friend in the world.  Also, become comfortable with condition includes in the preprocessor, and variable scope (EXTERN, etc).

-r
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 06:09:02 PM
Quote from: redskull on September 14, 2010, 05:19:28 PM
A properly written MAKE files is your best friend in the world.  Also, become comfortable with condition includes in the preprocessor, and variable scope (EXTERN, etc).

-r

Do you suggest having a pool of OBJ files in the project folder and using the MAKE file
to link them together? Or the MAKE files selects the souce code to Assemble and Link?

If a routine is used by many programs is it better to have it in a LIB?

The includes have to be all at he beginning of the prog, before the .DATA section, or you
can also choose a different location?
I mean, can I include a PROC in the middle of a source with the proper preprocessor directive?

Sorry for the n00bbyst questions, but I'm still quite ignorant in this field.  :P

Frank

Title: Re: DIVIDE ET IMPERA
Post by: redskull on September 14, 2010, 06:58:19 PM
Generally I prefer object files, but a lot depends on the circumstances.  I only use a static library if I have an actual "library"; a group of generalized functions that can be used across several programs.  If I'm just breaking up an application to make it more managable, i keep the object files around.

You can INCLUDE anything you want, anywhere you want; the assembler just "copy and pastes" the contents of the included file to that spot.  So, if you have a file with just a PROC, you could include that inside the .code segment of another program and it would work fine (assuming you don't do it inside another PROC).  That's bad style, though, and I would keep executable code of the include files.

-r
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 07:06:31 PM
Quote from: redskull on September 14, 2010, 06:58:19 PM
Generally I prefer object files, but a lot depends on the circumstances.  I only use a static library if I have an actual "library"; a group of generalized functions that can be used across several programs.  If I'm just breaking up an application to make it more managable, i keep the object files around.

You can INCLUDE anything you want, anywhere you want; the assembler just "copy and pastes" the contents of the included file to that spot.  So, if you have a file with just a PROC, you could include that inside the .code segment of another program and it would work fine (assuming you don't do it inside another PROC).  That's bad style, though, and I would keep executable code of the include files.

-r

Thanks redskull, this is much more clear for me.

I am not sure I properly grasp one sentence of yours :
I would keep executable code of the include files
what do you mean?
Title: Re: DIVIDE ET IMPERA
Post by: redskull on September 14, 2010, 07:24:54 PM
Include files should contain just assembler directices for definitions, such as EXTERN, PROTO, TEXTEQU, STRUCT, macros, etc, etc.  Keep anything that actually generates code (and obviously machine instructions themselves) in source files/object files.  For example, if two source files both need to use a defined 'foo' STRUCT, then you should have one common .INC file that contains the definition, and each .asm file include it somewhere near the top.  If you plan to use libraries and makefiles, you'll need a seperate include as well.

-r
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 07:38:05 PM
Quote from: redskull on September 14, 2010, 07:24:54 PM
Include files should contain just assembler directices for definitions, such as EXTERN, PROTO, TEXTEQU, STRUCT, macros, etc, etc.  Keep anything that actually generates code (and obviously machine instructions themselves) in source files/object files.  For example, if two source files both need to use a defined 'foo' STRUCT, then you should have one common .INC file that contains the definition, and each .asm file include it somewhere near the top.  If you plan to use libraries and makefiles, you'll need a seperate include as well.

-r


Oh, maybe you were talking about OBJ files when you said
QuoteI would keep executable code of the include files
this was confusing me, I was thinking about EXE files.

OK I got your points. Good suggestions. Thanks again.  :U

Frank
Title: Re: DIVIDE ET IMPERA
Post by: redskull on September 14, 2010, 08:02:05 PM
Quote from: redskull on September 14, 2010, 07:24:54 PM
I would keep executable code of the include files

"I would keep executable code OUT of the include files"

I just can't type  :red

-r
Title: Re: DIVIDE ET IMPERA
Post by: clive on September 14, 2010, 08:04:39 PM
At the end of the day you have to do what works best for you.

If you can partition the code into individual DLL's with clean, well defined, and stable interfaces, and you can handle situations where the versions might be mismatched (backward/forward compatibility) then EXE+DLL's is a good way to go.

I've managed projects which have one function per file, and have thousands of functions. It can be very hard to find things, and you need tools to realistically navigate the project (Understand C++). If many people are working on the project, it makes sense to keep the files small and specific, so each piece has a clear interface, and can be tested by itself. It is much more difficult for one person to keep a model of the entire project in their head, and different people need to understand their own sub-project and how it might interact with others.

With source code management (SCM, ie CVS, Subversion, Git, etc) you need to be able make a snapshot of the entire project, so that you can recreate an old version/release/branch from scratch by pulling out the entire snapshot. Also you learn to use merge tools (WinMerge, Araxis) to pull functions into and across different branches. They are also useful to understand what changed between code that worked, and code that failed, where bugs were introduced, etc.

Personally I prefer to develop code in a monolithic file, keeping things fairly modular and grouped together. When it becomes practical/realistic to break it into sub modules I will do that, but you'd want to limit the number of files to a few dozen. I'll do this either by putting the code in separate source files, or bring it into the primary code as an include file. Your tolerance level might be different, but editors/compilers/assemblers these days can load/process very large files, historically this was a limiting factor. Given that I use SCM, the fact I have multiple instances of the same file isn't too problematic, provided you don't mix up the internal ordering of the file, it is very easy to use merge tools to pick and chose code changes that need to brought in. The reason to keep the file count low is to ensure there aren't a lot of dependencies within the project, with no external dependencies, and to be able to keep track of it in your head. External dependencies are best handled by using a DLL, to provide a rigid interface. If the interface is more fluid then it makes more sense to pull it into the project, but try to provide/consider some partitioning so that you can pull it out of the project later if the interface becomes more solid, or you can make it common to multiple projects.

Use libraries where you can, the linker should be able to cherry pick the pieces it needs rather than pulling in the whole thing.

With an embedded mindset, I would also try to statically link as much as possible. It will make the file larger, but it's behaviour will be more predictable and it can stand by itself. It is a nightmare to provide technical support when you have no control of the DLL's on the target system. Even when using "standard" DLLs you can get systems that contain a near infinite spectrum of versions, some things you expect to work might not, and it's very hard to test all possible scenarios. That's not to say don't use "standard" DLLs, but rather consider what functions to use, and what systems you expect to run on.

Use MAKE files whenever possible, use a batch file if you only have a few files, but always try to automate the build process so you don't have to remember what compiler/assembler and options to use.

It's also quite important to note in the project documentation and source code, the versions of the toolset being used, and the expected compiler command line and options. This can be very helpful when you come back to something 10 or 20 years later, and you have to remember that the project expected to use the Microsoft "huge" model, or that certain optimization options on C 6.00 resulted in bad code generation in function xyz.
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 08:19:07 PM
Thanks clive,
many points to consider indeed.
I think I'm going to be the only developer, I've already gone past the point
of working with code, and team development in particular.
I'm learning MASM for fun, and I'll code something for my personal use/amusement.
It could become a big project nevertheless.
So probably I'll stick with static LIBs, MAKE files, Project folder, as a starting point.
These seems to be the more appropriate, according to your comments.

If I'll mix C/C++ and MASM code, the tools provided with C/C++ compilers could be
quite useful.

Frank
Title: Re: DIVIDE ET IMPERA
Post by: Gunther on September 14, 2010, 09:06:18 PM
I would like to underline every point of Clive's reply. Very important points.

Just another small note by me. It's mostly a good idea to comment your source code well, especially by writing assembly language applications. That's helpful by the program documentation (a weakness of many coders), by the maintaining, and last but not least, by navigation through the different source, include etc. files.

Gunther
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 09:40:58 PM
Quote from: Gunther on September 14, 2010, 09:06:18 PM
I would like to underline every point of Clive's reply. Very important points.

Just another small note by me. It's mostly a good idea to comment your source code well, especially by writing assembly language applications. That's helpful by the program documentation (a weakness of many coders), by the maintaining, and last but not least, by navigation through the different source, include etc. files.

Gunther


:U
Title: Re: DIVIDE ET IMPERA
Post by: jj2007 on September 14, 2010, 09:53:33 PM
Quote from: clive on September 14, 2010, 08:04:39 PM
Personally I prefer to develop code in a monolithic file

Good to see I am not the only one :bg
As you wrote, speed used to be a limiting factor, but nowadays you can handle 10-20k lines of code without measurable delays, so why split and start bothering with complex setups... the 12k lines of my editor assemble and link in less than 0.6 seconds with JWasm. And it's just cute to type hEdit and see immediately the 75 instances where that handle was used, and be sure there is no other tiny nasty little include file where that handle was misspelled or cleared by accident or whatever.
Title: Re: DIVIDE ET IMPERA
Post by: clive on September 14, 2010, 10:15:52 PM
Yes, speed and size. Didn't quite get that in, although did think about it later.

When it took your 4.77/8 MHz PC 5 minutes to compile something, you would usually want to minimize the amount of stuff it recompiled (small files, make building the ones that changed). You'd go off and have a coffee/tea break while the thing ground along. What took minutes now takes milliseconds. It changes the way you attack problems, and debug things, you adapt, but it does give you a different perspective than someone starting today clicking away on their IDE.
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 14, 2010, 10:17:57 PM
Quote from: jj2007 on September 14, 2010, 09:53:33 PM

...Speed used to be a limiting factor, but nowadays you can handle 10-20k lines of code without measurable delays, so why split and start bothering with complex setups... the 12k lines of my editor assemble and link in less than 0.6 seconds with JWasm. And it's just cute to type hEdit and see immediately the 75 instances where that handle was used, and be sure there is no other tiny nasty little include file where that handle was misspelled or cleared by accident or whatever.

If I understand your choice, you prefer to have single source code, with lots of MACROs and a static LIB [MASMBASIC], that is
similar, to some extent, to the guideline I'm going to follow.

Quote from: clive on September 14, 2010, 10:15:52 PM
Yes, speed and size. Didn't quite get that in, although did think about it later.

When it took your 4.77/8 MHz PC 5 minutes to compile something, you would usually want to minimize the amount of stuff it recompiled (small files, make building the ones that changed). You'd go off and have a coffee/tea break while the thing ground along. What took minutes now takes milliseconds. It changes the way you attack problems, and debug things, you adapt, but it does give you a different perspective than someone starting today clicking away on their IDE.

Well these are very good points indeed  :U
Title: Re: DIVIDE ET IMPERA
Post by: redskull on September 14, 2010, 10:51:32 PM
Take care to notice that one big file is NOT exactly the same as several little ones linked together; different modules also means differnt variable scoping.  A variable can be global to one module or global to *all* modules, so it can help you keep things organized (or drive you nuts tracking down missing references).

-r
Title: Re: DIVIDE ET IMPERA
Post by: Gunther on September 14, 2010, 11:33:14 PM
Quote from: redskull, September 14, 2010, 11:51:32 pmTake care to notice that one big file is NOT exactly the same as several little ones linked together; different modules also means different variable scoping.

Good point. One large source file or several small files might be in assembly language a matter of taste. But the picture is changed dramatically by writing blended code. The hole bunch of command line switches of some compilers makes it necessary, to split the source in parts, which are compiled different.

Gunther
Title: Re: DIVIDE ET IMPERA
Post by: frktons on September 15, 2010, 02:25:52 AM
Quote from: Gunther on September 14, 2010, 11:33:14 PM
Quote from: redskull, September 14, 2010, 11:51:32 pmTake care to notice that one big file is NOT exactly the same as several little ones linked together; different modules also means different variable scoping.

Good point. One large source file or several small files might be in assembly language a matter of taste. But the picture is changed dramatically by writing blended code. The hole bunch of command line switches of some compilers makes it necessary, to split the source in parts, which are compiled different.

Gunther


Well, as redskull says, we have to take care of variable scoping.
Regarding Assembly blended with C, I'm going for INLINE Assembly
for the time being, so no big problem until I switch to 64 bit programming.

Frank
Title: Re: DIVIDE ET IMPERA
Post by: GregL on September 15, 2010, 02:32:42 AM
I use static libraries to include. Exactly the same as the masm32 library is done. Each procedure in a separate .asm file, assembled into an .obj file and then all related .obj files linked into a .lib file to include in your program later. When it is done this way the linker only links in the procedures you actually use into your program.
Title: Re: DIVIDE ET IMPERA
Post by: ToutEnMasm on September 15, 2010, 06:31:07 AM
Hello,
What i can say on the subject:
-DLL are useful for shared resources.If there is further instances of your program running at the same time,the used resources are loaded only once and this made your code smaller.

-Only one file or further ?
This depend of the IDE you use to write your code.
You have to consider the time needed to navigate threw the code.
My ide made the search for you (as vcexpress do) with a right clic and there is only advantages to break the code in small pieces.Each file can have is own utility and things are clearer like that.



Title: Re: DIVIDE ET IMPERA
Post by: untio on September 15, 2010, 03:18:51 PM
Hi,
I am only a hobbyist programmer. I use dll when it can be used in more than a program and it does all its work. I have a project in sourceforge that calculates a calendar "josecalendar'. The calendar calculation is made in a dll and the program manages the window. A dll is useful if you want to use your code in more than one language and compiler, because linking object modules of two compilers, masm and gcc by example, can be a disaster. Object files, library files and source code can have a problem: the duplicity of names. Personally, to avoid this I give a name to each source module of two or three words. After that, every symbol inside a module starts with the first letter of the three words:
FilesListView.c
flvOnCreate();
And is better not to use variables from other modules. When I need one of then I create a local variable that receives the same value.
Please, forgive me if it is not useful.
Title: Re: DIVIDE ET IMPERA
Post by: oex on September 15, 2010, 04:45:00 PM
I tend to work in the 1,000ish function range of apps written in different languages including PHP/Javascript, VB and ASM.... Every language has it's quirks and just as you dont write English Right to Left you should generally organise your code based on the strengths of the languages.... I manage all my code (except VB) in notepad, writing my own management interfaces as my code base grows, I found this highly successful in PHP however what works in one language doesnt necessarily work in another, ASM is also proving very notepad friendly.... I dont like any text out of line, I work based on layout not bold text and colors, this is my personal preference, monotone type is perfect for my needs.... PHP and ASM can be equally hard once the size of the code base outweighs the complexity of coding the language.... Constantly analyse how you are maintaining your code, remember, like a simple algorithm, you have always got it wrong because there are always simpler and more efficient ways you can organise it....

Unlike some of the pros on this forum I have only 12 years coding experience (and no formal education past 16) so I scour every example for ideas and reasoning behind code and even layouts.... Good ideas for coding can be drawn from the most surprising subject matter and conversational topics :bg