I had a similar problem with .dat symbols and did not like the idea of solving it with a big, nasty, add_custom_command blob. Since Python is required for installation of PropWare, I chose to solve the problem by writing a Python script to handle the objcopy call on .dat files. In my CMakeDATInformation.cmake file, I define the CMAKE_DAT_COMPILE_OBJECT variable:
Since OmniaCreator is not currently slated for cross-platform support, you could skip the extra layer and just do yours as a cmd script.
I know you're talking about .cogc, not .dat, but if you're willing to use this philosophy it should be a straight-forward fix. I know that's how I'll be solving the problem tomorrow.
I don't understand why Steve's approach in SimpleIDE works to be honest. However, it does seem to work. The following Makefile seems to build the adc driver correctly in spite of the fact that there appears to be nothing in the .cog file that would cause it to be pulled from the library.
I've attached a zip file containing my entire test directory. This builds without any special handling of the .cog driver. However, I know I've found cases where this does not work. Any idea what I'm missing?
Edit: Could this be because other symbols are causing the .cog file to be include? For example, the register names (INA, OUTA, DIRA, etc) are defined in the .cog file.
I had a similar problem with .dat symbols and did not like the idea of solving it with a big, nasty, add_custom_command blob. Since Python is required for installation of PropWare, I chose to solve the problem by writing a Python script to handle the objcopy call on .dat files. In my CMakeDATInformation.cmake file, I define the CMAKE_DAT_COMPILE_OBJECT variable:
Since OmniaCreator is not currently slated for cross-platform support, you could skip the extra layer and just do yours as a cmd script.
I know you're talking about .cogc, not .dat, but if you're willing to use this philosophy it should be a straight-forward fix. I know that's how I'll be solving the problem tomorrow.
David
Hi David,
Not being familiar with how CMake works, I'm not sure exactly what you're doing here. Can you tell me what sequence of commands ends up getting executed?
FYI, here is Eric Smith's advice on how to solve this problem:
As I think David has already mentioned, the issue is that no symbols
from cogcB.cog are being used, so it's not being pulled out of the
library for linking. The __load_start_XXX symbol is *not* part of the
.cog file, it's created by the linker only after the .cog file is added
to the link, so that symbol cannot be used to force the link -- it's a
chicken and egg problem. We actually need to reference something from
the .cog file itself.
Any symbol in the .cog file that's used in the main program will force
the link. A simple way to do this is to declare
a variable in the .cogc file like:
extern unsigned int _load_start_toggle_fw_cog[];
const unsigned int *toggle_fw_code = _load_start_toggle_fw_cog;
Then have the cognew function use "toggle_fw_code" instead of
"_load_start_toggle_fw_code".
This works because "toggle_fw_code" will be a symbol defined in the .cog
file itself (not linker created) and so any reference to it will cause
the .cog file to be linked.
I've updated the cog_c_toggle demo in the default branch to demonstrate
this approach.
Not being familiar with how CMake works, I'm not sure exactly what you're doing here. Can you tell me what sequence of commands ends up getting executed?
CMake understands compiled languages in that there are always two steps: compiling and linking (or archiving). Because of that, you have (essentially) two steps to define for every language: a command to compile and a command to link. So the CMake variable `CMAKE_DAT_COMPILE_OBJECT` is a command that gets run on every input dat file. The command that runs as a result would be, for the file `pst.dat`:
Then the normal C linker or archiver can step in and do whatever else needs to be done.
The Python script copies the file to a system temp directory, runs object copy in that directory, and finally copies the result back to whatever the original directory was (all this because we have no control over the path of input/output files and the working directory).
I can run this when I get home tonight and show you the real commands if you'd like.
However, changing the symbol names isn't going to help us in this case, so it may have been a useless reply. It sounds to me like the real solution is as Eric Smith says - with creating a special symbol in the cogc file that can be more easily referenced by the invoker cog.
@David - My build system has no dependencies on python. This was HARD to achieve... See the bin/elf size scripts in the main directory versus the python versions of the main scripts.
@David - My build system has no dependencies on python. This was HARD to achieve... See the bin/elf size scripts in the main directory versus the python versions of the main scripts.
Sorry but I don't want to dive into learning CMake. I'd just like to see the sequence of propeller-elf-xxx commands are being issued and their parameters.
undefined reference to `__load_start_adcACpropab_cog'
Thanks Kye. This is the problem that Eric was trying to address in the quote I posted earlier. There is no way to solve it other than to use his approach of introducing a new symbol. It is either that or use the scheme that I proposed that involves two invocations of objcopy but no additional symbols. Unfortunately, both require Andy to change the Simple Libraries code.
Thanks for posting that quote of mine, David. Your analysis is spot on -- I don't know of any way to force a .cog file to be pulled out of a library without having some kind of symbol in it referenced (and the _load_start_XXX symbols are not in the object file, they are created by the linker only *after* the library resolution is finished). Of course if the .cog file is not actually in a library then there is no issue. I think my original advice (in the quote you provided) is still the best approach. Your objcopy solution will also work. Perhaps someone can come up with a better solution than these, but I'm not aware of it yet.
My work around is not a good solution. The linker will complain about duplicate symbols if you compile a cogc file in your main project. This issue has to be fixed in the library itself.
Thanks! That would be very helpful. I'm interested in what propeller-elf-xxx commands are generated and their arguments.
Here's the output resulting from a fresh compile of a basic program using PropWare. I've listed the files both before and after the process so you know what is generated.
This output does not contain a .dat file - it's the simplest case you can get: compile a single source file and link against the libs. A version with pst.dat is coming right up...
Personally, I like some color in my terminal (click the link for color image of the following text).
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ l -a
./ ../
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ l -a ..
./ ../ bin/ CMakeLists.txt Hello_Demo.cpp
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ cmake ..
-- The C compiler identification is GNU 4.6.1
-- The CXX compiler identification is GNU 4.6.1
-- LOADED: Generic-gcc-Propeller.cmake
-- Check for working C compiler: /opt/parallax/bin/propeller-elf-gcc
-- Check for working C compiler: /opt/parallax/bin/propeller-elf-gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /opt/parallax/bin/propeller-elf-gcc
-- Check for working CXX compiler: /opt/parallax/bin/propeller-elf-gcc -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - failed
-- Configuring done
-- Generating done
-- Build files have been written to: /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ make VERBOSE=1
/home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -H/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello -B/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin --check-build-system CMakeFiles/Makefile.cmake 0
/home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -E cmake_progress_start /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory `/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin'
make -f CMakeFiles/Hello_Demo.dir/build.make CMakeFiles/Hello_Demo.dir/depend
make[2]: Entering directory `/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin'
cd /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin && /home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -E cmake_depends "Unix Makefiles" /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles/Hello_Demo.dir/DependInfo.cmake --color=
Dependee "/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles/Hello_Demo.dir/DependInfo.cmake" is newer than depender "/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles/Hello_Demo.dir/depend.internal".
Dependee "/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles/Hello_Demo.dir/depend.internal".
Scanning dependencies of target Hello_Demo
make[2]: Leaving directory `/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin'
make -f CMakeFiles/Hello_Demo.dir/build.make CMakeFiles/Hello_Demo.dir/build
make[2]: Entering directory `/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin'
/home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -E cmake_progress_report /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles 1
[100%] Building CXX object CMakeFiles/Hello_Demo.dir/Hello_Demo.cpp.obj
/opt/parallax/bin/propeller-elf-gcc -fno-threadsafe-statics -fno-rtti -save-temps -Os -ffunction-sections -fdata-sections -m32bit-doubles -Wall -std=gnu++0x -mlmm -isystem /home/david/External/Kits/Embedded/Parallax/Library/PropWare/simple -isystem /home/david/External/Kits/Embedded/Parallax/Library/PropWare -o CMakeFiles/Hello_Demo.dir/Hello_Demo.cpp.obj -c /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/Hello_Demo.cpp
Linking C executable Hello_Demo.elf
/home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -E cmake_link_script CMakeFiles/Hello_Demo.dir/link.txt --verbose=1
/opt/parallax/bin/propeller-elf-gcc -save-temps -Os -ffunction-sections -fdata-sections -m32bit-doubles -Wall -std=c99 -mlmm -Wl,--gc-sections -oHello_Demo.elf CMakeFiles/Hello_Demo.dir/Hello_Demo.cpp.obj /home/david/External/Kits/Embedded/Parallax/Library/PropWare/bin/libpropeller/source/lmm/libLibpropeller_lmm.a /home/david/External/Kits/Embedded/Parallax/Library/PropWare/bin/simple/lmm/libSimple_lmm.a /home/david/External/Kits/Embedded/Parallax/Library/PropWare/bin/PropWare/lmm/libPropWare_lmm.a -ltiny
make[2]: Leaving directory `/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin'
/home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -E cmake_progress_report /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles 1
[100%] Built target Hello_Demo
make[1]: Leaving directory `/home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin'
/home/david/reusable/cmake-3.0.2-Linux-i386/bin/cmake -E cmake_progress_start /home/david/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin/CMakeFiles 0
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ l -a
./ ../ CMakeFiles/ CMakeCache.txt cmake_install.cmake Hello_Demo.elf* Hello_Demo.ii Hello_Demo.s Makefile
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$
Of course, when you don't run with VERBOSE option, the output is much cleaner:
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ make clean
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$ make
[100%] Building CXX object CMakeFiles/Hello_Demo.dir/Hello_Demo.cpp.obj
Linking C executable Hello_Demo.elf
[100%] Built target Hello_Demo
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/Hello/bin$
I'm trying to use Eric's method of creating a dummy variable and referencing that instead of load_start... directly.
Here's my .cogcpp file:
#include <PropWare/uart/bufferedduplexuart.h>
extern unsigned int _load_start_bufferedduplexuart_cog[];
unsigned int *buffered_duplex_uart_driver = _load_start_bufferedduplexuart_cog;
_NAKED int main () {
const PropWare::Pin pin(PropWare::Pin::P16, PropWare::Pin::OUT);
while (1) {
pin.toggle();
waitcnt(250 * MILLISECOND + CNT);
}
}
and here's the compilation procedure:
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/PropWare_BufferedDuplexUART$ /opt/parallax/bin/propeller-elf-gcc -fno-threadsafe-statics -fno-rtti -Os -m32bit-doubles -std=gnu++0x -mlmm -I/home/david/External/Kits/Embedded/Parallax/Library/PropWare -o BufferedDuplexUART_Demo.cpp.obj -c BufferedDuplexUART_Demo.cpp
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/PropWare_BufferedDuplexUART$ /opt/parallax/bin/propeller-elf-gcc -fno-threadsafe-statics -fno-rtti -mcog -xc++ -Os -m32bit-doubles -std=gnu++0x -I/home/david/External/Kits/Embedded/Parallax/Library/PropWare -o bufferedduplexuart.cogcpp.cog -c bufferedduplexuart.cogcpp
david@balrogJr:~/External/Kits/Embedded/Parallax/Library/PropWare/Examples/PropWare_BufferedDuplexUART$ /opt/parallax/bin/propeller-elf-gcc -Os -m32bit-doubles -Wall -std=c99 -mlmm -oBufferedDuplexUART_Demo.elf BufferedDuplexUART_Demo.cpp.obj bufferedduplexuart.cogcpp.cog
bufferedduplexuart.cogcpp.cog: In function `_main':
(.text+0x0): multiple definition of `_main'
BufferedDuplexUART_Demo.cpp.obj:(.text+0x0): first defined here
bufferedduplexuart.cogcpp.cog: In function `_buffered_duplex_uart_driver':
(.data+0x0): undefined reference to `__load_start_bufferedduplexuart_cog'
collect2: ld returned 1 exit status
I still can't seem to get the special variable linked in. Any idea what I'm doing wrong? Does the variable name depend on the file extension? I tried changing it up a number of ways to include/exclude the cogcpp and cog and I just can't find anything that works.
The name chosen by the linker for the sections does depend directly on the file name -- it is the file name with any non-alphabetic characters (like '.') replaced with underscores. So for a file like bufferedduplexart.cogcpp.cog the section will be bufferedduplexart_cogcpp_cog and the load start symbol will be _load_start_bufferedduplexart_cogcpp_cog.
Comments
I had a similar problem with .dat symbols and did not like the idea of solving it with a big, nasty, add_custom_command blob. Since Python is required for installation of PropWare, I chose to solve the problem by writing a Python script to handle the objcopy call on .dat files. In my CMakeDATInformation.cmake file, I define the CMAKE_DAT_COMPILE_OBJECT variable:
Since OmniaCreator is not currently slated for cross-platform support, you could skip the extra layer and just do yours as a cmd script.
I know you're talking about .cogc, not .dat, but if you're willing to use this philosophy it should be a straight-forward fix. I know that's how I'll be solving the problem tomorrow.
David
Edit: Could this be because other symbols are causing the .cog file to be include? For example, the register names (INA, OUTA, DIRA, etc) are defined in the .cog file.
test.zip
Not being familiar with how CMake works, I'm not sure exactly what you're doing here. Can you tell me what sequence of commands ends up getting executed?
This looks like an excellent fix for the problem. Could the Learn libraries all be updated appropriately?
CMake understands compiled languages in that there are always two steps: compiling and linking (or archiving). Because of that, you have (essentially) two steps to define for every language: a command to compile and a command to link. So the CMake variable `CMAKE_DAT_COMPILE_OBJECT` is a command that gets run on every input dat file. The command that runs as a result would be, for the file `pst.dat`: Then the normal C linker or archiver can step in and do whatever else needs to be done.
The Python script copies the file to a system temp directory, runs object copy in that directory, and finally copies the result back to whatever the original directory was (all this because we have no control over the path of input/output files and the working directory).
I can run this when I get home tonight and show you the real commands if you'd like.
However, changing the symbol names isn't going to help us in this case, so it may have been a useless reply. It sounds to me like the real solution is as Eric Smith says - with creating a special symbol in the cogc file that can be more easily referenced by the invoker cog.
David
https://github.com/omniacreator/propeller-cmake/blob/master/cmake/platform/Propeller.cmake
@David - My build system has no dependencies on python. This was HARD to achieve... See the bin/elf size scripts in the main directory versus the python versions of the main scripts.
Here's my failing compile output: http://forums.parallax.com/attachment.php?attachmentid=111995&d=1416170615
Eric
How do we make this happen? Change seems small and straight-forward. I'd be happy to make it and submit a patch if that'd help move the process along.
Here's the output resulting from a fresh compile of a basic program using PropWare. I've listed the files both before and after the process so you know what is generated.
This output does not contain a .dat file - it's the simplest case you can get: compile a single source file and link against the libs. A version with pst.dat is coming right up...
Personally, I like some color in my terminal (click the link for color image of the following text).
Of course, when you don't run with VERBOSE option, the output is much cleaner:
Color image
Here's my .cogcpp file:
and here's the compilation procedure:
I still can't seem to get the special variable linked in. Any idea what I'm doing wrong? Does the variable name depend on the file extension? I tried changing it up a number of ways to include/exclude the cogcpp and cog and I just can't find anything that works.