This is where understanding the difference between define and declare, which many programmers do not understand, pays off. Let's say you have a project named MyProject. Let's further assume that MyProject.ino is the file that contains setup() and loop(). However, you want to have a second source code file, call it Support.cpp, to have access to globals defined in the INO file. To make it simple, let's say we need access to a variable name mySensor in the program files. Try this:
#ifndef BEENHERE // This is the MyProject.ino file
int mySensor; // This is a data definition: attribute list plus allocated memory
// more code...
The support code file, Support.cpp looks like this:
#ifndef BEENHERE // This is the top of the Support.cpp file
// whatever the support code is...
The project's header file looks like this:
#ifndef BEENHERE // This is the top of the MyProject.h file
#define BEENHERE // Note: This is where the symbolic constant is defined
extern int mySensor; // This is a data declaration; it's only an attribute list, no allocated memory
// Any other header file stuff you might need (e.g., other globals, #includes, etc.)
When the compiler reads the MyProject.ino file, BEENHERE is not yet defined, so the #include "MyProject.h" preprocessor directive causes the header file to be read into the program. In that header file, the first thing that happens is that BEENHERE gets defined. Next, it reads the extern int mySensor declaration. In essense, what this says is: "The variable mySensor is defined somewhere else, but let me use it as an int variable named mySensor with global scope". The compiler will then read the rest of the header file.
When the compiler is done reading the header file, it then continues to read the rest of MyProject.ino. It finds the int mySensor statement, which is the definition of mySensor. The compiler now allocates a memory address (lvalue) for that variable. Because it now has a known memory address, mySensor is defined in the symbol table.
Now look at Support.h. Because BEENHERE is defined, the header file is not included. This avoids "double including" the content of the header file. However, because mySensor is now defined in the symbol table, you can use mySensor anywhere you wish within the Support.cpp header file.
Note that I named only the file with setup() and loop() in it with a secondary file name of INO. I always use CPP (C Plus-Plus) for all other source code (non-header) files in the same project. This has several advantages. First, it always appears as the left-most tab in the IDE, with the other files in alpha order. Second, because of that placement and its secondary INO file name, I know instantly where setup() and loop() are located in the project. Finally, it now appears that the compiler knows which files are unchanged from the previous compile and it only recompiles those that are now "dirty". In other words, if can perform incremental compiles. (My current project has 19 files in it, and this is a real time saver.) If you name them all with INO secondary file names, it doesn't appear to perform incremental compiles, but I'm not positive on this.