How do you declare the Solidity compiler version with pragma, and what do the caret ^ and range forms mean?
pragma solidity fixes which compiler version(s) may build the file; a bare version pins exactly, ^ allows that version and any newer patch within the same minor line, and a range sets explicit bounds.
pragma solidity 0.8.8; // exactly 0.8.8
pragma solidity ^0.8.8; // 0.8.8 up to (not including) 0.9.0
pragma solidity >=0.8.7 <0.9.0; // an explicit range
Solidity is young and changes fast, so every contract must state the compiler it expects. The caret ^0.8.8 accepts 0.8.8, 0.8.9, 0.8.10, … but stops before 0.9.0 — you accept newer patch/minor releases in the 0.8 line but not a breaking 0.9. A bare 0.8.8 demands that exact version. When files with different pragmas are imported together, their allowed ranges must overlap, or the compiler errors with "source file requires a different compiler version."
Go deeper:
Solidity docs: version pragma — exact, caret, and range version semantics.