Code Kata: Project Euler #3 + CMake distributions
Posted by md
on April 13, 2008

This weekend, I tackled the Project Euler problem #3:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
Pretty straightforward: Just test and recurse.
The core of the implementation is here:
std::set<ull> Problem3::_findFactor(ull number, ull startFactor ) {
std::set<ull> retval;
for( ull factor = startFactor; factor < = number; factor += 1) {
if (number % factor == 0) {
retval.insert(factor);
std::set<ull> recursive = _findFactor(number / factor, factor);
retval.insert(recursive.begin(), recursive.end());
break;
}
}
return retval;
}
Please note that "ull" is a typedef for unsigned long long. For increasing integers, I test whether it is a factor of the given number. If yes, add it to the set of result values and descent one level into the recursion.
In addition, I extended my CMake infrastructure: You can now roll distributions based on CPack. In my oppinion you should start having a distribution target as early as possible within your development cycle. This way, you're always ready to ship/deploy your software, i.e. for beta testers. Ship early, ship often... And of course automatically. When I type "make release", CMake builds the software in release mode ("-O3") and rolls several distributions. This is the output:
Run CPack packaging tool...
CPack: Create package using PackageMaker
CPack: Install projects
CPack: - Run preinstall target for: PROBLEM3
CPack: - Install project: PROBLEM3
CPack: Compress package
Building in backwards compatible mode
Preverifying PROBLEM3
Preverifying PROBLEM3
Checking bundle identifiers
Checking package configuration
Checking contents
Loading contents
Checking for ZeroLink
Building PROBLEM3
Building PROBLEM3
Creating shell
Copying scripts
Writing description
Writing bundle versions
Copying resources
Creating Requirements
Creating permission hierarchy
Creating Bill-of-Materials file
Archiving files
Creating Info.plist
CPack: Finalize package
CPack: Package /Users/gonium/Projects/project-euler/trunk/problem3/build/PROBLEM3-0.2.0-Darwin.dmg generated.
CPack: Create package using STGZ
CPack: Install projects
CPack: - Run preinstall target for: PROBLEM3
CPack: - Install project: PROBLEM3
CPack: Compress package
CPack: Finalize package
CPack: Package /Users/gonium/Projects/project-euler/trunk/problem3/build/PROBLEM3-0.2.0-Darwin.sh generated.
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: PROBLEM3
CPack: - Install project: PROBLEM3
CPack: Compress package
CPack: Finalize package
CPack: Package /Users/gonium/Projects/project-euler/trunk/problem3/build/PROBLEM3-0.2.0-Darwin.tar.gz generated.
As you can see, a DMG image, a self-extracting shell installer and a tar.gz are built. The DMG contains all metadata for a nice MacOS installer - for Windows, a NSIS-based installer would have been created. CPack reuses the dependency information from my CMakeLists.txt files, so I don't have to maintain another place and avoid duplication.
You simply add CPack to your toplevel CMakeLists.txt:
# add some files to the installation target
INSTALL(FILES README.txt COPYRIGHT.txt DESTINATION share/PROBLEM3/doc)
# CPACK packaging
INCLUDE(InstallRequiredSystemLibraries)
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Project Euler Problem 3")
SET(CPACK_PACKAGE_VENDOR "Mathias Dalheimer")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.txt")
SET(CPACK_RESOURCE_FILE_LICENSE"${CMAKE_CURRENT_SOURCE_DIR}/COPYRIGHT.txt")
SET(CPACK_PACKAGE_VERSION_MAJOR ${V_MAJOR})
SET(CPACK_PACKAGE_VERSION_MINOR ${V_MINOR})
SET(CPACK_PACKAGE_VERSION_PATCH ${V_PATCH})
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}")
SET(CPACK_PACKAGE_EXECUTABLES "pe-problem3" "Solves Project Euler problem 3")
INCLUDE(CPack)
I choose to add the resulting binary in a subsequent CMakeLists.txt where the binary is compiled:
INSTALL(PROGRAMS ${PROBLEM3_BINARY_DIR}/src/pe-problem3 DESTINATION bin)
Pretty easy and maintainable :-) You can get the source package from the download page.
Picture taken by
8#X and CCed on flickr.