Jump to content
 
  • 0

Issues with inline after switching to XC32 v2.15 - "multiple definition of"


Orunmila
 Share

Question

  • Member

I just downloaded XC32 V2.15, I was using V2.10 before. I find that some of my projects no longer compile. On my first check I noticed that the problems seem to occur when inline functions are used and the same header where the inline implementation is done is included in more than one compilation unit?

Has any of you seen similar issues?

I will investigate further and post here if I arrive at an answer.

 

UPDATE: Ok, I managed to make a small test project to replicate the problem. I am attaching it here. 

TestInlineXC32_2.15.zip

 

Next I am going to test this on some other compilers to see what the deal is. I have confirmed that with that project when you switch it to V2.10 or older it all compiles just fine, but if you use V2.15 it failes to link with the following error:

"/Applications/microchip/xc32/v2.15/bin/xc32-gcc"   -mprocessor=32MZ2048EFM100  -o dist/default/production/TestInlineXC32_2.15.X.production.elf build/default/production/main.o build/default/production/otherFile.o          -DXPRJ_default=default  -legacy-libc    -Wl,--defsym=__MPLAB_BUILD=1,--no-code-in-dinit,--no-dinit-in-serial-mem,-Map="dist/default/production/TestInlineXC32_2.15.X.production.map",--memorysummary,dist/default/production/memoryfile.xml
nbproject/Makefile-default.mk:151: recipe for target 'dist/default/production/TestInlineXC32_2.15.X.production.hex' failed
make[2]: Leaving directory '/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X'
nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failed
make[1]: Leaving directory '/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
build/default/production/otherFile.o: In function `myInlineFunction':
/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X/inlinedheader.h:6: multiple definition of `myInlineFunction'
build/default/production/main.o:/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X/inlinedheader.h:6: first defined here
/Applications/microchip/xc32/v2.15/bin/bin/gcc/pic32mx/4.8.3/../../../../bin/pic32m-ld: Link terminated due to previous error(s).
collect2: error: ld returned 255 exit status
make[2]: *** [dist/default/production/TestInlineXC32_2.15.X.production.hex] Error 255
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2

BUILD FAILED (exit value 2, total time: 680ms)

 

 

 

Link to comment
Share on other sites

10 answers to this question

Recommended Posts

  • 0
  • Member

Ok, got some feedback that the REAL bug is that the code compiled in v2.10, this "bug" was fixed in v2.15.

The way to get the behavior back to matching v2.10 is to pass the linker flag  "--allow-multiple-definition" which will allow inline funcitons declared in header files included in multiple compilation units to link successfully.

Of course if you do it that way (place the implementation in the header) then the code SHOULD only compile when you have used "static inline", if you just placed inline, like I did in my example, it is not supposed to compile, and as I discovered it also does not compile on GCC or LLVM. When you use "static inline" correctly it compiles on all the mentioned versions of all the mentioned compilers, because the code is then correct 🙂

Link to comment
Share on other sites

  • 1
  • Member

It seems that in 2.15 they changed how the command line options are interpreted.

in 2.10, there was a -fgnu89-inline option that ensured the inlines operated in a particular way (the GNU89 way).  

In 2.15 it seems this option is being quietly ignored.  You can test by removing the option from the command line when you build in 2.10 and then you should see the same error.

  • Helpful 1
Link to comment
Share on other sites

  • 0
  • Member

OMG you are a genius! That was it! 

I carefully read the release notes and this was not mentioned at all. Very disappointing, this cost me a couple of hours of struggling today and someone else here has an open issue with Microchip support to try and get a Harmony 2.05 project to build with the new compiler and have not manageed to resolve their issue in a week now, so this is costing customers as lot of time and we all know time is money!

I will go ahead and change my code to C99 semantics for inline, and I guess I will have to also update the Harmony code myself if I want to use the latest compiler. Sigh ...

I was just busy testing, as promised in my update above, on LLVM when you posted that btw. Of course since I was using G89 semantics for inline the project was not compiling on LLVM either, except there it was complaining that there was no definition for the symbol instead of complaining about a duplicate definition.

When I changed the inline definition to extern inline in my header the error swapped around. Now LLVM was complaining that the symbol was no longer missing, but I now had a duplicate symbol. Strangely this compiled just fine on XC32? Had to brush up on my C99 inline semantics a bit and found that I probably want static inline, and yes that compiles on both LLVM and XC32, so I guess I am going to go with that for now.

BTW. The release notes contain only this for XC32 v2.15:

New Features in MPLAB® XC32 v2.15

  • New Part Support -- This release introduces initial support for the MEC15xx family of Embedded Controllers as well as the ATSAMx7, ATSAME54/D51, and ATSAMC2x/D2x families of 32-bit microcontrollers.

  • Tightly-Coupled Memory (TCM) on SAMx7 MCUs -- The SAM family features a low-latency SRAM interface called Tightly-Coupled Memory (TCM). To support this interface, XC32 provides a new tcm attribute. You can apply this attribute to a function or variable and it will be placed into instruction or data TCM as appropriate. (e.g. uint32_t __attribute__((tcm)) var;)

    To enable TCM, pass the -mitcm=<size_in_bytes> and the -mdtcm=<size_in_bytes> options to xc32-gcc/g++ both when compiling and when linking. (See the device datasheet for the size values supported by your target device.) The device-specific startup code and the device-specific linker script then work together to set up, initialize, and enable TCM at startup, before your main() function is called. With this option enabled, the linker allocates the vector table to ITCM, improving both interrupt latency and latency determinism.

    Also for improved determinism, you may also choose to move your stack to DTCM by passing the -mstack-in-tcm option to xc32-gcc/g++ at compile and link time. The linker will allocate a stack to DTCM and the startup code will transfer the stack from System SRAM to DTCM before calling your main() function.

  • Issues Fixed -- See the Fixed Issues section for information on bug fixes addressed in this release.

  • 64-bit executables coming soon -- A future release of XC32 will be provided only as 64-bit executables for Windows x64, Linux x64, and MacOS x64. We will no longer provide 32-bit executables.

Link to comment
Share on other sites

  • 0
  • Member

Ok, now I am sleuthing to figure out what is exactly going on. At first I thought that the problem was just that -fgnu89-inline is being ignored, but the plot thickens! 

When I remove the std as well as the -fgnu89-inline from the project I attached above it still builds fine on v2.10 and fails on v2.15, so they are not only ignoring the setting, they are also defaulting things differently ...

At first I suspected that the default mode was changed from GNU89 to C99 in this compiler version, but when I check for it __STDC_VERSION__ is not defined when trying to compile this with either compiler, which means it is not defaulting suddenly to C99. This leaves me with thinking that it may have changed the default from GNU89 to GNU99?

So my first test was to pass -std=c99 to v2.10, and yes it fails identically to the v2.15 with no standard specification, so I thought this makes sense. I think compiled on v2.10 with -std=gnu89 and as expected it compiles fine, but then I tried to compile on v2.15 with -std=gnu89 and nope, inline does not work with gnu89 semantics either.

So it seems like they are not in fact ignoring the -fgnu89-inline flag, it seems that the implementation for that has somehow been ripped out of the heart of the compiler, because even if you try and force it to use gnu89 as the C dialect it fails on v2.15...

I will wait and see if we can get an answer from Microchip on this, and update here if I do.

Link to comment
Share on other sites

  • 0

Oh, I see now. You have to include the body, otherwise the compiler complains (if -Winline is used):

my_inline_func.h:4:17: warning: inlining failed in call to 'inl_func': function body not available [-Winline]

And it works fine with 2.10, I see nice inlined functions in the disassembly:

 

 

inlfunc_210.png

Link to comment
Share on other sites

  • 0
  • Member
47 minutes ago, holdmybeer said:

And now it works with 2.15.

Try to add "extern" to your inline function, this worked for me:

I mentioned in my first response that this is incorrect, I tried it and it works on XC32 but it should not work according to the standard, so the implemenation seems to be incorrect. Most importantly although this works on XC32, it does NOT work on any other compiler in my project.

Quote

"When I changed the inline definition to extern inline in my header the error swapped around. Now LLVM was complaining that the symbol was no longer missing, but I now had a duplicate symbol. "

I need a solution which works on all compilers, just FYI my project runs on 12 different compilers, so making it work on XC32 is less than 10% of my problem here ...

So we originally used GNU89 semantics for inline, which means it works as long as all compilers can handle this. GCC can handle this if you pass in the command line switch -fgnu89-inline  OR if you set the C dialect to be GNU89. Both cases should work, and does in v2.10. 

The problem is that in v2.15 neither of these options work, so it is now impossible to use GNU89 semantics for inline by either method. This means the compiler now does C99 or C89 only and can no longer support GNU89 inlining, which is a little strange as GCC, which it is based on, happily handles this...

Link to comment
Share on other sites

  • 0
  • Member
7 hours ago, holdmybeer said:

I just had a look at your test project and really wonder why you put the definition of a function in a header file. Since you include that header file with the definition in two C files, you end up with two conflicting definitions, don't you?

Of course the answer here is that the semantics for inline in C89 do not exist (there is no such thing as inline), in GNU89 you can define a C function in a C file and place inline on it as a hint for the optimizer, BUT in C99 and C11 this is illegal, in C99 and C11 the standard specifies that the only legal way to use inline is to have the function body in the header file ...

Read this for some background:

https://gustedt.wordpress.com/2010/11/29/myth-and-reality-about-inline-in-c99/

This is the relevant part "So you’d have to put the implementation of such candidate functions in header files."

EDIT: To be super pedantic about it, the standard does not exactly say you must place the definition in the header file, but if you want to use the function from more than one C file you will have to do exactly that for it to work.

Edited by Orunmila
clarification
  • Helpful 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

 


×
×
  • Create New...