You will need to build a cross compiler toolchain (binutils and GCC). I.e. i686-pc-elf-gcc for 32 bit or x86_64-pc-elf-gcc for 64 bit. The compiler that comes with your OS is built for a different target and may have downstream patches, esp. if you're on Ubuntu. Things may seem to work initially but you will encounter strange bugs sooner or later.
Build a bootable and debuggable ELF file, not a flat binary. All it takes is a slightly different linker script. You won't get very far without a debugger on bare metal projects.
You need to zero fill .bss section in the boot code before jumping to C code.
I recommend using gas instead of nasm. You might like Intel syntax but you'll need inline (at&t) assembly in C code anyway. Nicer to have just one syntax. It's just an assembler syntax, you will get used to it in a matter of hours
Use a makefile. Fancy build systems (e.g. cmake) aren't nice with kernel images.
See below for examples. The first one isn't my project but I contributed the linker script, Makefile and README for making bootable ELFs. The latter is my x86_64 toy kernel project from years ago.