I have a header file from the Pokemon Emerald decompilation codebase (https://github.com/pret/pokeemerald) which uses types defined in a different header file, but does not include that header, or include ANY header files for that matter, yet still the code somehow compiles. My neovim LSP says the u8
and bool8
types for example are unrecognised since gba/types.h
header file is not included. However, my VScode LSP which is using intellisense does recognise these types for some reason. Does anyone know what is going on here? Is there some sort of implicit include happening here? These types are used all over the entire codebase, and I did a search for "#include "gba/
", and there are almost no occurences. So these header files are not being included in the source or header files, but somehow the code compiles anyway.
Header file using types without including headers for reference:
// file name: include/field_control_avatar.h
#ifndef GUARD_FIELDCONTROLAVATAR_H
#define GUARD_FIELDCONTROLAVATAR_H
struct FieldInput
{
bool8 pressedAButton:1;
bool8 checkStandardWildEncounter:1;
bool8 pressedStartButton:1;
bool8 pressedSelectButton:1;
bool8 heldDirection:1;
bool8 heldDirection2:1;
bool8 tookStep:1;
bool8 pressedBButton:1;
bool8 input_field_1_0:1;
bool8 input_field_1_1:1;
bool8 input_field_1_2:1;
bool8 input_field_1_3:1;
bool8 input_field_1_4:1;
bool8 input_field_1_5:1;
bool8 input_field_1_6:1;
bool8 input_field_1_7:1;
u8 dpadDirection;
};
void FieldClearPlayerInput(struct FieldInput *pStruct);
void FieldGetPlayerInput(struct FieldInput *pStruct, u16 keys, u16 heldKeys);
int ProcessPlayerFieldInput(struct FieldInput *pStruct);
void overworld_poison_timer_set(void);
void RestartWildEncounterImmunitySteps(void);
const u8 *GetObjectEventScriptPointerPlayerFacing(void);
bool8 TryDoDiveWarp(struct MapPosition *position, u16 b);
int SetCableClubWarp(void);
u8 TrySetDiveWarp(void);
const u8 *GetInteractedLinkPlayerScript(struct MapPosition *position, u8 metatileBehavior, u8 direction);
u8 *GetCoordEventScriptAtMapPosition(struct MapPosition *position);
void ClearPoisonStepCounter(void);
#endif // GUARD_FIELDCONTROLAVATAR_H
i don't find it THAT weird that the code compiles to be honest, because it's using a special compiler called agbcc
(https://github.com/pret/agbcc), and maybe the build system is like automatically including these files. But my VSCode LSP is just using clang
, yet it recognises these types without including headers. So I'm not sure what's going on.
CodePudding user response:
It appears that almost every C
file in that repro starts with #include "global.h"
which starts with:
#include <string.h>
#include <limits.h>
#include "config.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines.
#include "gba/gba.h"
#include "constants/global.h"
#include "constants/flags.h"
#include "constants/vars.h"
#include "constants/species.h"
#include "constants/pokedex.h"
#include "constants/berry.h"
#include "constants/maps.h"
#include "constants/pokemon.h"
#include "constants/easy_chat.h"
#include "constants/trainer_hill.h"
And gba.h starts with:
#include "gba/defines.h"
#include "gba/io_reg.h"
#include "gba/types.h"
#include "gba/multiboot.h"
#include "gba/syscall.h"
#include "gba/macro.h"
#include "gba/isagbprint.h"
So the includes are occurring transitively.
I haven't looked further, but presumably this is how it all compiles.