cmake build problem when building code for avr - cmake

I am trying to build a sample project for avr atmega328p. And I am facing a strange issue. I have following directory structure.
inc/core/device_support.h
src/main.c
src/core/device_support.c
I have two project setups, one using make and another one using cmake. When I build using make everything works fine. but when I use cmake it doesn't compile ok. ( .text section is not same if I run avr-size -A myProject.elf and it doesn't run correctly on target mcu). But if I run the compile command manually in cmake project directory with build directory as working directory everything works fine.
I have narrowed down the problem to the fact that if we run compile command form core /home/user/avr/build/core it doesn't work, and If I run command while in /home/user/avr/build build directory It works fine. I have no clue to why this may be happening.
My question is why being on different directory messes up compilation and how can I fix it in cmake.
with make I have something like:
avr-gcc -DARDUINO=10808 -DF_CPU=160000000L -I/home/user/avr/inc/core -mmcu=atmega328p -ffunction-sections -fdata-sections -MMD -flto -std=gnu11 -fno-fat-lto-objects -Os -w -g -MD -MT /home/user/avr/src/core/device_support.c -o /home/user/avr/build/core/device_support.o
and with cmake auto generated script I have:
cd /home/user/avr/build/core && avr-gcc -DARDUINO=10808 -DF_CPU=160000000L -I/home/user/avr/inc/core -mmcu=atmega328p -ffunction-sections -fdata-sections -MMD -flto -std=gnu11 -fno-fat-lto-objects -Os -w -g -MD -MT -o src/CMakeFiles/core.dir/src/core/device_support.o /home/user/avr/src/core/device_support.c
UPDATE 01:
avr-size -A myProject.elf output (cmake):
section size addr
.data 0 8388864
.text 740 0
.bss 9 8388864
.comment 17 0
.note.gnu.avr.deviceinfo 64 0
.debug_aranges 120 0
.debug_info 3537 0
.debug_abbrev 1965 0
.debug_line 1044 0
.debug_frame 124 0
.debug_str 1175 0
.debug_loc 843 0
.debug_ranges 40 0
Total 9678
avr-size -A myProject.elf output (make):
section size addr
.data 0 8388864
.text 930 0
.bss 9 8388864
.comment 17 0
.note.gnu.avr.deviceinfo 64 0
.debug_aranges 104 0
.debug_info 3559 0
.debug_abbrev 2002 0
.debug_line 1134 0
.debug_frame 180 0
.debug_str 1139 0
.debug_loc 1154 0
.debug_ranges 24 0
Total 10316
You can see the difference in .text section. Its a simple led blink code When I run this on device in cmake case LED stays on at sometimes and completely off at others. And If I compile the same code manually by running the same commands from cmake's output, but with build directory as my working directory then LED blinks as expected.
There are no errors during build in either case. The only difference is being in build directory. If I build manually and my working directory is not build then It fails in this case as well. For some reason being in build directory during compilation is important and I have no clue why.
Update 02:
Example code has been upload to : https://github.com/systemangle/mcve_avr
Please see project readme.

For some reason being in build directory during compilation is important and I have no clue why
Then you probably already have the answer. The problem doesn't seem to be CMake related.
May be you can try an in-source build with cmake and see what happen.
Otherwise if you want to mimic the hand-written Makefile behaviour you can avoid using any add_subdirectory and only write a big fat CMakeLists.txt at the root of your project.
All that said, if compilation output vary depending on where you are when the compiler is invoked then I think you'd better off asking question to the people providing the cross-compiler about this weird behavior.
Did you try hand compilation a file while being in a different directory?
Does this change the outputed object file?

Related

cmake add_custom_command introduces false dependency unless add_custom_target also used

I'm using cmake to build some libraries, all of which generate some of their files.
I've created the generated files using add_custom_command(), but I've discovered something which seems like a false dependency. If a downstream library has a generated file and links to an upstream library, the downstream library sources will not start to compile until the upstream library is completely built. With many libraries (more than 50) in my project, this false dependency causes serialization in the build.
What's curious is that I also noticed that if an explicit add_custom_target() for the generated file is used with add_dependencies(), the false dependency no longer exists, and the files in the downstream library will compile concurrently with the ones in the upstream library. So I have a workaround, but is this expected behavior?
Using Cmake 1.19, Ninja 1.10.2.
The following is a minimal CMakeLists.txt file that shows what happens. The WORKS option conditionally adds the add_custom_target() and add_dependencies() clauses which cause it to work (quickly). The files foo.c and bar.c are empty, and I'm building in a subdirectory of the CMakeLists.txt directory.
I put a file called /tmp/x which is a wrapper around cc that sleeps to show the serialization occur:
#!/bin/bash -e
echo "mycc" $(date)
sleep 4
exec /usr/bin/cc $*
Here is the CMakeLists.txt:
cmake_minimum_required(VERSION 3.19)
project(test)
option(WORKS "false dependency gone if WORKS set to ON" OFF)
add_library(foo
foo.c
)
add_library(bar
bar.c
bargen.h
)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
add_custom_command(OUTPUT bargen.h
COMMAND touch bargen.h
)
if (${WORKS})
add_custom_target(generate_file
DEPENDS bargen.h
)
add_dependencies(bar generate_file)
endif()
target_link_libraries(bar PUBLIC foo)
Build it like this and you will see the serialization: bar.c will not start to compile until after foo.c has finished compiling (in fact, not until after the foo library is built). (I'm explicitly choosing '-j 4' to ensure Ninja will try to build in parallel).
cmake -DWORKS=OFF -G Ninja -DCMAKE_C_COMPILER=/tmp/x .. && ninja clean && ninja -j 4 -v | grep mycc
This shows the following output:
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/rhb/Downloads/cmake-anomaly/build
[1/1] Cleaning all built files...
Cleaning... 5 files.
mycc Sat Jan 2 15:15:25 EST 2021
mycc Sat Jan 2 15:15:29 EST 2021
Now build it like this and you'll see that bar.c compiles concurrently with foo.c:
cmake -DWORKS=ON -G Ninja -DCMAKE_C_COMPILER=/tmp/x .. && ninja clean && ninja -j 4 -v | grep mycc
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/rhb/Downloads/cmake-anomaly/build
[1/1] Cleaning all built files...
Cleaning... 5 files.
mycc Sat Jan 2 15:15:37 EST 2021
mycc Sat Jan 2 15:15:37 EST 2021
This was reported as a cmake issue and recently fixed with a new argument to add_custom_command. This fix will be released with the next cmake version (3.27).
DEPENDS_EXPLICIT_ONLY
.. versionadded:: 3.27
Indicate that the command's DEPENDS argument represents all files
required by the command and implicit dependencies are not required.
Without this option, if any target uses the output of the custom command,
CMake will consider that target's dependencies as implicit dependencies for
the custom command in case this custom command requires files implicitly
created by those targets.
Only the Ninja Generators actually use this information to remove
unnecessary implicit dependencies.

Issues using cmake on cygwin

I have a project which was previously linux only in makefile.
I have successfully migrated it to cmake and that works fine, it compiles in pure linux (makefile --> so) and pure windows (visual studio --> dll) with no issue. It also compiles fine on linux for windows (using mingw --> dll).
However, for integration and script compatibility issues, I have to generate and build the code for windows (dll) but on a cygwin environment (with cygwin's gcc providing a dll), like the old makefile used to do.
(I have to do this way, due to external constraints)
I have installed both "make" and "cmake" packages on my cygwin.
When I try to generate a makefile in the cygwin console, it gets stuck:
$ cmake -G "Unix Makefiles" ../Sources
[ -- misc CMake prints from my CMakeLists.txt -- ]
-- Configuring done
[ -- stuck - nothing happens here -- ]
When I stop it (ctrl-C), it says nothing and the "Makefile" file is present in my build directory, so I try and compile it:
$ make
[ -- misc CMake prints from my CMakeLists.txt -- ]
-- Configuring done
[ -- stuck - nothing happens here -- ]
It seems to be re-generating all all over again (I get my cmake prints again, the Makefile file disappears then reappears and the command gets stuck at the same stage again).
This time, when I stop it, it prints the following message:
$ make
[ -- misc CMake prints from my CMakeLists.txt -- ]
-- Configuring done
make: *** [Makefile:224: cmake_check_build_system] Interrupt
I've tried to look up the Makefile and it seems to be the following command that blocks:
cmake_check_build_system:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check- build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system
I searched and found this thread, so it seems to just be a way to set the directories.
I've tried running it manually and the result is the same:
$ cmake -H../Sources -B. --check-build-system CMakeFiles/Makefile.cmake 0
[ -- misc CMake prints from my CMakeLists.txt -- ]
-- Configuring done
[ -- stuck - nothing happens here -- ]
I don't know what I'm doing wrong and I'm stuck, could someone help me?
Edit: running make in verbose mode gives a little more information:
$ make VERBOSE=1
/usr/bin/cmake.exe -H/cygdrive/e/Projects/MyProject/Sources -B/cygdrive/e/Projects/MyProject/Build_Cygwin --check-build-system CMakeFiles/Makefile.cmake 0
Re-run cmake: build system dependency is missing
[ -- misc CMake prints from my CMakeLists.txt -- ]
-- Configuring done
As suggested by Fred, I used --trace to get more info --> there was absolutely nothing after Configuring done.
Then, as suggested by Tsyvarev, I simplified the CMakeLists to the bare minimum, where it was ok. Then I added things bit by bit until I identified the issue.
It came from cmake path variables that contained drive letters (like "E:/...") that made cmake go nuts and get stuck.
I made a small macro to patch all path variable, replacing drive letters by "/cygdrive/[drive letter]/..." and after patching them all, everything went back to normal. For those interested:
macro(PatchPath PATHTOPATCH OUTPUT_VAR)
if(${TARGET_SYSTEM_TYPE} MATCHES "cygwin")
string(SUBSTRING ${PATHTOPATCH} 0 1 CYG_DRIVE)
string(TOLOWER ${CYG_DRIVE} CYG_DRIVE)
string(SUBSTRING ${PATHTOPATCH} 2 -1 TMP_END_OF_PATH)
set(${OUTPUT_VAR} "/cygdrive/${CYG_DRIVE}${TMP_END_OF_PATH}")
endif()
endmacro()
Thanks everyone!

Creating .dylib from C Source Code At the Command Line

Context:
I have downloaded the source code for "Discount", which is a simple C program. The code is online here: http://www.pell.portland.or.us/~orc/Code/discount/
What I Need:
I want to turn this code into a .dylib file that I can then bundle with my Cocoa app. Once I HAVE the dylib file, I'm fine. What I'm struggling with is how to CREATE the dylib file in the first place.
Before you yell at me, YES I have Googled my ass off. But I cannot find a straightforward explanation of exactly what I need to do at the command line to compile this collection of C source files into a .dylib. Everything I come across is convoluted or talks about building a dylib project in Xcode or is outdated. (I've found some references for doing it with GCC, but I'd like to use LLVM.)
Make Install
From what I gather, running the typical "make install" is supposed to put a .dylib file into /usr/lib, but that does not seem to be happening for me.
Bottom Line:
Once I've downloaded the Discount source code, what do I need to do at the command line to create a .dylib file on OS X 10.8.2? Thank you.
That project by default doesn't create a dynamic library on Mac OS X. I made a quick patch to the makefile that seems to work:
From a3d6793c5f291d253b8e7aa99e5534503808c325 Mon Sep 17 00:00:00 2001
From: Carl Norum <carl#norum.ca>
Date: Thu, 31 Jan 2013 16:59:24 -0800
Subject: [PATCH] Patch to generate a dynamic library.
---
Makefile | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 8532e70..11805dd 100644
--- a/Makefile
+++ b/Makefile
## -27,6 +27,7 ## install: $(PGMS) $(DESTDIR)$(BINDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(INCDIR)
/usr/bin/install -s -m 755 $(PGMS) $(DESTDIR)$(BINDIR)
./librarian.sh install libmarkdown VERSION $(DESTDIR)$(LIBDIR)
/usr/bin/install -m 444 mkdio.h $(DESTDIR)$(INCDIR)
+ /usr/bin/install -m 755 $(MKDLIB).dylib $(DESTDIR)$(LIBDIR)
install.everything: install install.samples install.man
## -82,7 +83,7 ## theme: theme.o $(MKDLIB) mkdio.h
mkd2html: mkd2html.o $(MKDLIB) mkdio.h
$(CC) $(LFLAGS) -o mkd2html mkd2html.o -lmarkdown
-markdown: main.o pgm_options.o $(MKDLIB)
+markdown: main.o pgm_options.o $(MKDLIB) $(MKDLIB).dylib
$(CC) $(LFLAGS) -o markdown main.o pgm_options.o -lmarkdown
makepage: makepage.c pgm_options.o $(MKDLIB) mkdio.h
## -94,6 +95,9 ## pgm_options.o: pgm_options.c mkdio.h config.h
main.o: main.c mkdio.h config.h
$(CC) -I. -c main.c
+$(MKDLIB).dylib: $(OBJS)
+ $(CC) -dynamiclib -o $(MKDLIB).dylib $(OBJS)
+
$(MKDLIB): $(OBJS)
./librarian.sh make $(MKDLIB) VERSION $(OBJS)
--
1.7.12.1
You can apply that to your tree after running the configure script and before building and it should work out. If you just want the easy part, running:
cc -Wno-implicit-int -I. -dynamiclib -o libmarkdown.dylib mkdio.o markdown.o dumptree.o generate.o resource.o docheader.o version.o toc.o css.o xml.o Csio.o xmlpage.o basename.o emmatch.o github_flavoured.o setup.o tags.o html5.o flags.o
on your command line after building the regular package should generate the dynamic library for you. You can then install it yoursef.

Problems adding DKMS support to kernel module

I'm trying to add DKMS support in a kernel module i'm working on.
I have placed the kernel module source with a static lib to be linked against in the following directory:
/usr/src/dpx/1.0
With the following files:
dkms.conf
Makefile
dpxmtt.c
lib.a
dkms.conf file is like this:
MAKE="make"
CLEAN="make clean"
BUILT_MODULE_NAME=dpx
BUILT_MODULE_LOCATION=src/
DEST_MODULE_LOCATION=/kernel/drivers/input/touchscreen
PACKAGE_NAME=dpxm
PACKAGE_VERSION=1.0
REMAKE_INITRD=yes
And the makefile is like this:
EXTRA_CFLAGS+=-DLINUX_DRIVER -mhard-float
obj-m += dpx.o
dpx-objs:= dpxmtt.o ../source/lib.a
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
The ../source/lib.a is an hack since when the makefile is invoked by the dkms building system it was saying that it couldn't be found in directory (the build directory), but since it was being copied to the source directory, i'm referencing it relatively.
When I call
sudo dkms build -m dpx -v 1.0
The result is almost perfect:
santos#NS-PC:~$ sudo dkms build -m dpx -v 1.0
Kernel preparation unnecessary for this kernel. Skipping...
Building module:
cleaning build area....
make KERNELRELEASE=3.0.0-14-generic....
ERROR (dkms apport): binary package for dpx: 1.0 not found
Error! Build of dpx.ko failed for: 3.0.0-14-generic (i686)
Consult the make.log in the build directory
/var/lib/dkms/dpx/1.0/build/ for more information.
nsantos#NS-PC:~$
And the content of the log file is:
DKMS make.log for dpx-1.0 for kernel 3.0.0-14-generic (i686)
Thu Jan 19 11:07:54 WET 2012
make -C /lib/modules/3.0.0-14-generic/build M=/var/lib/dkms/dpx/1.0/build modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-14-generic'
CC [M] /var/lib/dkms/dpx/1.0/build/dpxmtt.o
LD [M] /var/lib/dkms/dpx/1.0/build/dpx.o
Building modules, stage 2.
MODPOST 1 modules
CC /var/lib/dkms/dpx/1.0/build/dpx.mod.o
LD [M] /var/lib/dkms/dpx/1.0/build/dpx.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-14-generic'
The module was built correctly but it ends with the error:
ERROR (dkms apport): binary package for dpx: 1.0 not found
Error! Build of dpx.ko failed for: 3.0.0-14-generic (i686)
And I don't know what it means. Does anybody know?
Using:
$(shell uname -r)
in the Makefile it might be also wrong! The "shell uname -r" refers to the currently running kernel, but the main reason to use the dkms it's because it offers an automated method to recompile the kernel modules that reside outside of the kernel tree for every newly installed kernel. What i mean is that the Makefile might refers to a different kernel which the dkms is building the module for.
Use:
${kernelver} instead.
I had a similar problem. I think your BUILT_MODULE_LOCATION is set incorrectly to the src directory. It should be set in your example to the current directory, or you can just omit this variable and dkms would default to the current directory.

cygwin g++ produces no output

I just installed g++ from cygwin, when I try to compile a C++ file I am not getting any executable produced by the compiler, see example below. What's going wrong?
Directory of C:\helloworld
01/02/2011 04:50 PM .
01/02/2011 04:50 PM ..
01/02/2011 04:48 PM 94 helloworld.cpp
1 File(s) 94 bytes
2 Dir(s) 24,658,272,256 bytes free
C:\helloworld>g++-4 helloworld.cpp
C:\helloworld>dir
Volume in drive C is OS
Volume Serial Number is C47B-942D
Directory of C:\helloworld
01/02/2011 04:50 PM .
01/02/2011 04:50 PM ..
01/02/2011 04:48 PM 94 helloworld.cpp
1 File(s) 94 bytes
2 Dir(s) 24,657,747,968 bytes free
C:\helloworld>
For others who end up here with g++ producing no output.
I solved it by running cygcheck -s in the cygwin terminal window. This checks (amongst others) for multiple instances of cygwin1.dll. In my case WinAVR was causing problems, uinstalling did the the trick
This link was also helpful in getting Cygwin to run properly: http://thehacklist.blogspot.nl/2009/04/cygwin-ls-command-not-found.html
The problem seems to be (judging from your C:\ prompt) that you are not running Cygwin. Try double-clicking the Cygwin icon.
You should be able to run any Cygwin program from the DOS prompt since Cygwin is not an operating system like Linux, it is primarily a special DLL that programs link against + tools. However, in this case, I suspect that path issues are preventing g++ from running, either the path to g++ itself or to some libs g++ requires. Cygwin apps are notoriously bad at giving any info when they don't run, and the solution is to run them via strace.
C:\cygwin\bin> strace g++
Then any issues will be shown in a windows dialog box.