The literal answer is that compilers are really easy to write when the source and destination language are the same and you don't want any optimisation. E.g. write the x64 machine code out as raw bytes and cat is good enough to turn it into x64 machine code.
Difficulty increases as the source and target languages become less similar, as more ambitious performance optimisations are attempted, as more comprehensive type/lint/warning style systems are implemented and as performance constraints on the compiler itself tighten.
So a compiler that takes imprecise scribblings, spots errors in them, and emits asymptotically perfect machine code for heterogenous distributed systems in real time is quite dramatically more complicated than cat.