Way To Not Have To Use Export and Import In CA65?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Way To Not Have To Use Export and Import In CA65?
by on (#160686)
That's basically it. I was just wondering if there was a way to just declare something to be universal across all files so you wouldn't have to keep messing with ".export" and ".import" on everything. I'm assuming the purpose of this was so that you could have two different routines with the same name or something, like "start", but I always just name everything different anyway, like "metasprite_start" or "animation_engine_start", so it doesn't effect me, it's just a bit of a nuisance. It's not the biggest deal in the world, but it's a bit nicer.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160687)
You can simply use .include to combine all your assembly files into one giant translation unit, instead of assembling each separately. That's really all you're asking for.

The purpose of requiring an explicit import/export is the same as its purpose in C and C++; it provides encapsulation, i.e. each module is self contained and the communication points between modules are very clearly marked by import/export. (This was a huge practical advantage historically re: compile times, though most assembly projects made around here compile very fast these days.)

If you want to use some common set of imports in a lot of files, create a header file, and include it in each of those files. (This is also the C approach.) Also, you can use .global instead of .export/.import, which is very convenient for this purpose (it's basically a smart .import + .export, i.e. automatically figures out which of the two it is).
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160704)
It's interesting, how differently unidentified symbols are handled in ca65. Other assemblers that I've worked with just carry foreign symbols into the linker stage, and then start throwing errors if a mentioned symbol can't be found in any object files.

...at least I think that's how they do it. Haven't done this in a while.

On subject, I just have a universal file full of .globals and that handles everything.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160716)
nicklausw wrote:
Other assemblers that I've worked with just carry foreign symbols into the linker stage, and then start throwing errors if a mentioned symbol can't be found in any object files.

There's a similar mode in ca65 called .autoimport +, but the manual warns against it because you don't learn about a typo until the linker. And if a typo happens to match another valid symbol private to another file, you don't learn about it at all until you end up with some heisenbug or mandelbug at runtime.

Quote:
On subject, I just have a universal file full of .globals and that handles everything.

Same here. I have one file for NES register address definitions, one for global symbols, and possibly one for each distinct reusable library that a program uses.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160720)
rainwarrior wrote:
You can simply use .include to combine all your assembly files into one giant translation unit, instead of assembling each separately. That's really all you're asking for.

So, in my main game file, I say ".include (name of another file for the game)" for every file that is part of the game and then I won't have to worry about anything?
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160721)
Yes, I was suggesting you assemble only one file, and from that file just .include all your other source files.

However, tepples has just pointed out that it has .autoimport which also does what you want, just in a different manner.

I wouldn't particularly recommend either approach (I much prefer headers and some degree of encapsulation), but do as you will.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160783)
rainwarrior wrote:
I wouldn't particularly recommend either approach (I much prefer headers and some degree of encapsulation), but do as you will.

You're kind of scarring me now... :lol: What real disadvantages are there to just saying "include"? Is it just processing power? I can't imagine it would ever take that long to assemble, but my crappy Celeron (named as such because it has the processing power of celery) never seems to disappoint...
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160803)
In practice, the build time of my biggest 6502 assembly projects (Haunted: Halloween '85 and RHDE: Furniture Fight) is dominated by things outside ca65, mostly conversion of graphical assets. (The conversion tools are written in Python not C for programmer convenience, and Python's interpreter is nowhere near as fast as modern ECMAScript interpreters.) Fortunately, the makefile re-runs conversions only when the source PNG files have changed. It's a much bigger issue for Haunted, which has long scrolling levels, than for RHDE, whose assets are a title screen, a font, background tiles, and unit animation frames.

In either case, once the assets have been converted, ca65 fully assembles these projects in a couple seconds even on a single core Atom. It might have been more of a problem in the past on machines with weaker CPU and RAM than even a 10-year-old Pentium 4. It's still a problem in C++, especially with deeply nested templates and high -O settings. On the other hand, the trend toward interprocedural optimization between translation units is a return to #include in spirit. It allows, for example, more aggressive inlining of short functions.

Image
Not that kind of aggressive inlining


The true disadvantage of .include "something.s", where something.s contains code rather than just headers, is the same loss of encapsulation and typo-proofing as with .autoimport +.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160806)
I'm pretty comfortable with fake encapsulation: In my programs, all variables, subroutines, tables, etc. of a program module start with that module's name followed by an underscore. Only local names are unprefixed.

I considered assembling the modules separately, but because of the little amount of ROM and RAM I always feel the need to mix things up a bit so that everything fits within the system constraints.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160826)
tepples, the obscurity of your jokes scares me a little sometimes.

While the design of only re-building modified modules seems pretty nice, I can't seem to figure out how to make a makefile do that. Mine just build everything always, as far as I know.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160828)
Makefile 101:

Makefiles are sensitive to whitespace. And, unfortunately, to kind of whitespace.

The very rudimentary syntax you need is:
Code:
DestinationFile: List Of Dependency Files
(tab)Command to run to generate DestinationFile from Dependency Files
(blank line with NO WHITESPACE on it)
Make will then only run that command when any of the List Of Dependency Files is newer than Destination File.

For example:
Code:
test.o: test.asm
(tab)cl65 -t nes -c --create-dep test.d -Cl --listing test.lst -o test.o test.asm


Now, it seems a little silly to have to type "test.o" and "test.asm" twice, so Make lets you say "The destination file", "The source files", and "the first thing in the list of source files" with "$@", "$?", and "$<" respectively:
Code:
test.o: test.asm
(tab)cl65 -t nes -c --create-dep $<.d -Cl --listing $<.lst -o $@ $<


Even more usefully, Make will let you say "Any time you want a file of type X, if prerequisite Y exists, do this, by using "%" in the Destination/Dependency listing:
Code:
%.o: %.asm
(tab)cl65 -t nes -c --create-dep $<.d -Cl -I --listing $<.lst -o $@ $<
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160833)
tepples wrote:
ca65 fully assembles these projects in a couple seconds even on a single core Atom.

Yeah, I don't think I have anything to worry about... I was worried it would get to be like video rendering times or something by the way it was said.

Anyway, last chance before I delete all the .exports and .imports in favor of .include... It's just ridiculous to say things like

Code:
.export Player1IdleAnimationTable
.export Player1WalkingAnimationTable
.export Player1JumpingAnimationTable
.export SmallExplosionAnimationTable
.export LargeExplosionAnimationTable

and so on and so forth.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160836)
Just organize your project in whatever way you find helps you work efficiently and effectively.

I don't have a killer answer as to why I favour separate modules to the "all in one" approach, but it's a preference formed over many years of working on larger projects. For the record, I did work on one PS3 title that was compiled as a small handful of C++ translation units, #include style, though this was really only done in desperation to improve Unreal 3 compile times, very specific to this one project and its compiler (and on the other platforms we did NOT do this).

For the cases you just listed, though, why do you need to export "Player1IdleAnimationTable"? Why not keep that table in the same module as the code that uses it? Then you don't need to export it, and no other module needs to import it (or know anything about it). If it's banked data vs fixed code, remember you can use multiple .segment directives in a single module, you don't have to organize your files by bank.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160857)
rainwarrior wrote:
For the cases you just listed, though, why do you need to export "Player1IdleAnimationTable"?

Perhaps because it's created by an external tool, such as the metasprite creation tool that I proposed to psycopathicteen in this post.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#160861)
tepples wrote:
rainwarrior wrote:
For the cases you just listed, though, why do you need to export "Player1IdleAnimationTable"?

Perhaps because it's created by an external tool, such as the metasprite creation tool that I proposed to psycopathicteen in this post.

If it's created by an external tool, then the tool can also create the .exports and an include file with the corresponding .imports.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161022)
Well, I've screwed myself over trying to make everything use .include... It isn't that bad though. Basically, I accidentally messed up the .bat file I use that's supposed to tell ca65 to put the game together or something. Because It's only one file instead of multiple, I changed it to only include the main file for assembling, but when I did that, I also accidentally deleted the batch file code for saying to create the SNES if the game was assembled correctly. Well, it still gives me a .lst file. :lol:

Anyway, this is the batch file I ruined. I think Koitsu made it, although he doesn't really seem to be around anymore.

Code:
@echo off
setlocal
set rom=Game.sfc
set objs=
if not exist objs mkdir objs
del /Q *.lst
goto :main

:assemble
echo Assembling... %1.asm
ca65.exe -l %1.lst %1.asm -o objs\%1.obj
if %errorlevel% equ 0 set objs=%objs% objs\%1.obj
goto :eof

:failure
echo Assembler or linker failed; see above output for details.
endlocal
exit /b %errorlevel%
goto :eof

:main
call :assemble Game             || goto failure

REM If things were successful, we'll have an .SFC file
if exist %rom% (
  echo.
  echo Results:
  dir %rom%
)
endlocal

I think the code I accidentally deleted was right under

Code:
:main
call :assemble Game             || goto failure

If that helps. I'm assuming fixing it should be easy? :oops:


Fortunately though, it assembled the game in (as far as I can tell anyway) the same time as earlier.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161053)
Not sure if this will help, but my build setup is (thanks to lidnariq's tutorial):

a makefile with this inside: (note, implies that you want output of snes.sfc and have config file called snes.cfg)
Code:
CC = ca65
LD = ld65
SFILES = $(wildcard *.s)
OFILES = $(subst .s,.o,$(SFILES))

all: $(OFILES)
   $(LD) $(OFILES) -o snes.sfc -C snes.cfg

%.o: %.s
   $(CC) $< -o $@


and my batch file that I run: (note, implies that you have ucon64, but that's easily removable)
Code:
@echo off
make
if errorlevel 1 goto end
ucon64 -q --snes --nhd --chk snes.sfc >nul 2>&1
echo assembly completed.
if exist snes.sfc start snes.sfc
exit
:end
echo assembly failed.
exit


">nul 2>&1" silences the output of a program, for anyone who's curious.


If you're looking to build just one big module, then you can just get rid of the makefile and have this batch:
Code:
@echo off
ca65 %1.asm -o %1.o
if errorlevel 1 goto end
ld65 -o %1.sfc %1.o -C snes.cfg
if errorlevel 1 goto end
ucon64 -q --snes --nhd --chk %1.sfc >nul 2>&1
echo assembly completed.
if exist %1.sfc start %1.sfc
exit
:end
echo assembly failed.
exit

...with the args as the name of the main file without a file extension.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161081)
Quote:
If you're looking to build just one big module, then you can just get rid of the makefile and have this batch:

It didn't work. It says a message that's onscreen for a split second before it closes the command prompt. I don't know what it says because I didn't have enough time to read it. I named it "build", and typed in "build" into the command prompt and it didn't work, so I typed in "build game.asm" and it still didn't work. I think I'll just have to look for an old zip file I uploaded here that has in included in it.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161082)
Add the single line "pause" in the .bat file before each instance of the word "exit".
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161083)
Espozo wrote:
Quote:
If you're looking to build just one big module, then you can just get rid of the makefile and have this batch:

It didn't work. It says a message that's onscreen for a split second before it closes the command prompt. I don't know what it says because I didn't have enough time to read it. I named it "build", and typed in "build" into the command prompt and it didn't work, so I typed in "build game.asm" and it still didn't work. I think I'll just have to look for an old zip file I uploaded here that has in included in it.

try "build game".
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161085)
I recommend you take a look at Undisbeliever's projects on github to learn how to structure a project using ca65 and Make.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161091)
Yay! :) I looked around at the code, and I saw it kept saying "%1" for things, and I experimented and just replaced it with the name of my file and it worked to where I only had to just double click the batch file. I like how it automatically jumps to play the game if it assembled correctly.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161094)
A double-clickable batch wrapper around a makefile is straightforward:
Code:
@echo off
make
if errorlevel 1 goto Error
C\path\to\fceux.exe mygame.nes
goto End
:Error
pause
:End
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161098)
What tepples? I'm good now.
Re: Way To Not Have To Use Export and Import In CA65?
by on (#161105)
Espozo wrote:
Yay! :) I looked around at the code, and I saw it kept saying "%1" for things, and I experimented and just replaced it with the name of my file and it worked to where I only had to just double click the batch file. I like how it automatically jumps to play the game if it assembled correctly.

Glad you like it, hehe.

I never make my batch scripts pause because I code with a program that automatically runs the script and shows me its output with the touch of a button.