CMake + precompiled headers + MSVC. Окончательный вариант

Как неожиданно выяснилось, предыдущие варианты (раз, два, три) оказались неправильными. Публикую окончательный правильный вариант использование precompiled headers при компиляции nmake или в Visual Studio 2008:

CMakeLists.txt

macro( use_precompiled_header SRC_LIST_VAR HDR_FILE SRC_FILE )
 
    get_filename_component( PCH_HEADER ${HDR_FILE} NAME )
    get_filename_component( PCH_BINARY ${HDR_FILE} NAME_WE )
 
    set( PCH_BINARY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${PCH_BINARY}.pch" )
 
    if (MSVC)
        set( SRC_LIST ${${SRC_LIST_VAR}} )
 
        set_source_files_properties( ${SRC_LIST} PROPERTIES
            COMPILE_FLAGS "/Yu${PCH_HEADER} /Fp${PCH_BINARY}"
            OBJECT_DEPENDS "${PCH_BINARY}" )
 
        set_source_files_properties( ${SRC_FILE} PROPERTIES
            COMPILE_FLAGS "/Yc${PCH_HEADER} /Fp${PCH_BINARY}"
            OBJECT_OUTPUTS "${PCH_BINARY}"
            OBJECT_DEPENDS "" )
    endif(MSVC)
endmacro( use_precompiled_header )

Особенное внимание обратите на использование:

file( GLOB_RECURSE CORE_SRC *.cpp )
use_precompiled_header( CORE_SRC precompiled.h precompiled.cpp )

CORE_SRC — это НАЗВАНИЕ переменной, а не сама переменная.

P.S. С версии CMake 3.16.0 доступна команда target_precompiled_headers(), которая позволяет без лишних усилий работать с precompiled headers.

Используем OgreBullet в своем проекте с помощью CMake

В нашей системе сборки все сторонние библиотеки компилируются вместе с проектом, поэтому стандартное FIND_PACKAGE нам не подходит. Значит, CMakeLists.txt из сборки OgreBullet тоже идет лесом. Поэтому приходится извращаться на свой лад.

CMakeLists.txt

# Название проекта
project( OgreBullet )
 
# Разделяем исходники для двух precompiled headers
file( GLOB_RECURSE OGRE_BULLET_COLLISIONS Collisions/*.cpp )
file( GLOB_RECURSE OGRE_BULLET_DYNAMICS Dynamics/*.cpp )
 
# Папки для поиска #include
include_directories(
    ${GLOBAL_INCLUDE_DIR}/Ogre
    ${GLOBAL_INCLUDE_DIR}/OgreBullet/Collisions
    ${GLOBAL_INCLUDE_DIR}/OgreBullet/Dynamics
    ${GLOBAL_LIB_DIR}/Bullet
    ${GLOBAL_LIB_DIR}/Bullet/BulletConvexDecomposition
    ${GLOBAL_LIB_DIR}/Bullet )
 
# Определяем макрос для использования precompiled headers
macro(use_precompiled_header SRC_LIST HDR_FILE SRC_FILE)
    # Выделяем имя заголовка без пути
    get_filename_component(PCH_HEADER ${HDR_FILE} NAME)
    # Выделям имя заголовка без расширения и пути
    get_filename_component(PCH_BINARY ${HDR_FILE} NAME_WE)
    # Полный путь к созданному pch
    set(PCH_BINARY "${CMAKE_CURRENT_BINARY_DIR}/${PCH_BINARY}.pch")
 
    if (MSVC)
        # Для precompiled.cpp создаем pch, указывая файл (OBJECT_OUTPUTS), который создается в результате комманды 
        set_source_files_properties( ${SRC_FILE} PROPERTIES
            COMPILE_FLAGS "/Yc${PCH_HEADER} /Fp${PCH_BINARY}"
            OBJECT_OUTPUTS "${PCH_BINARY}" )
        # Для каждого исходника в списке, задаем зависимость от precompiled.pch и указываем использовать его параметром "/Yu"
        foreach( SOURCE ${SRC_LIST} )
            set_source_files_properties( ${SOURCE} PROPERTIES 
                COMPILE_FLAGS "/Yu${PCH_HEADER}" 
                OBJECT_DEPENDS "${PCH_BINARY}" )
        endforeach( SOURCE ${SRC_LIST} )
 
    endif(MSVC)
 
endmacro(use_precompiled_header)
 
# Создаем precompiled header для Collisions
use_precompiled_header( OGRE_BULLET_COLLISIONS
    "${GLOBAL_INCLUDE_DIR}/OgreBullet/Collisions/OgreBulletCollisions.h" Collisions/OgreBulletCollisionsPrecompiled.cpp )
 
# Создаем precompiled header для Dynamics
use_precompiled_header( OGRE_BULLET_DYNAMICS
    "${GLOBAL_INCLUDE_DIR}/OgreBullet/Dynamics/OgreBulletDynamics.h" Dynamics/OgreBulletDynamicsPrecompiled.cpp )
 
# Объединим два списка файлов для удобства
set( OGRE_BULLET_SRC
    "${OGRE_BULLET_COLLISIONS}"
    "${OGRE_BULLET_DYNAMICS}" )
 
# Добавляем define для использования precompiled headers библиотекой OgreBullet
add_definitions( -D_PRECOMP )
# Profit!
add_library( ogre_bullet STATIC ${OGRE_BULLET_SRC} )

UPDATE: Окончательный вариант precompiled headers смотрим здесь.

Советы неопытному водителю

Написать эту заметку меня побудило поведение друга, который купил себе машину, обладая нулевым стажем и гипертрофированным самомнением. Совершенно нормальным у него считается погудеть заснувшему спереди водителю, а когда тот начнет двигаться — заглохнуть самому и, с красным от смущения лицом, попытаться завести свое ведро.

Немного о себе: права получил в 2002 году, с тех пор периодически ездил на отцовской пятёрке BMW. Спустя некоторое время, я купил себе Nissan Note и с тех пор уже три с половиной года езжу на ней. В основном с работы, на работу, на дачу и просто так развлечения ради. Иногда приходилось выезжать в другие города. Особенно запомнилось новогоднее посещение Пскова, куда я ехал с температурой в 39 градусов и опытом вождения пару месяцев, затем посещение Ярославля после долгой затяжной депрессии.

Для начала, хочу рассказать о типах неопытных водителей. Их на мой взгляд четыре.

  • опытный пассажир: продолжительное время катается рядом с водителем на пассажирском сиденье, знает город и (как ему кажется) является опытным водителем в теории, весьма самоуверенный тип за рулём
  • водитель без прав: до получения прав очень часто ездил за рулем автомобиля (по даче, нелегально по городу, по деревне и так далее)
  • чайник: ни разу до получения прав не ездил за рулем автомобиля, очень редко бывал пассажиром в такси, в основном предпочитает общественный транспорт
  • мажор: совмещает в себе «опытного пассажира» и «водителя без прав», ездит, как правило, на дорогой иномарке с блатными номерами, не глохнет на перекрестках только из-за полностью компьютеризированной машины, не так часто врезается за счет надежности и безопасности авто, скорее всего имеет вторую машину попроще, чтобы ездить на «тайные встречи» (для тех, кто в теме)

Куда ехать? Я водитель

Итак, приступим к советам.

  • на первых порах повесьте знак «Начинающий водитель». Спрячьте куда-нибудь свое чувство собственной важности — на дороге это верный путь к аварии и смело вешайте этот знак. Не обязательно обклеивать всю машину, как делают некоторые. Достаточно одного знака на заднем стекле
  • НИКОГДА не выходите из себя за рулем. Терпение и еще раз терпение. Внутренне вы должны быть АБСОЛЮТНО спокойны. Ругаться разрешено и даже приветствуется. Гудеть и моргать фарами в бешенстве, размахивать руками или вообще выбегать из машины с перекошенным от злости лицом категорически ЗАПРЕЩЕНО
  • соблюдайте БОКОВУЮ дистанцию. Если вы проезжаете мимо припаркованной машины, будьте готовы к тому, что в ней в любой момент может открыться дверь слева или справа, по закону подлости в сторону вашего автомобиля
  • ЗАБУДЬТЕ о приметах на дороге. Не будьте идиотом, ВКЛЮЧИТЕ мозги
  • если вас подрезали или назревает авария, в первую очередь необходимо предотвратить аварию с помощью педалей и руля, а уж затем оскорбленно жать в клаксон. Пока другой будет гудеть, исходя соплями от бешенства, у вас есть шанс предотвратить аварию
  • соблюдайте достаточно большую дистанцию с машиной, которой управляет неадекватный водитель
  • включайте указатели поворотов как минимум за 100 метров до поворота и за три секунды до перестроения
  • почаще крутите головой вправо и влево, не доверяйте зеркалам бокового вида, помните о мёртвых зонах
  • НИКОГДА не мстите водителю машины, которая вас подрезала или обидела каким-то иным образом. Это очень опасно и многократно увеличивает вероятность аварии
  • ВЫКЛЮЧИТЕ МУЗЫКУ в машине. Пока у вас недостаточно опыта, необходимо слушать как работает двигатель. Это поможет вам не заглохнуть, когда вы стартуете
  • ПОЧАЩЕ выезжайте с пассажирами. Оптимальный вариант: с друзьями куда-нибудь в черте города. Что-нибудь отвезти, кого-нибудь забрать и все в таком духе.
  • НЕ ОТВЛЕКАЙТЕСЬ за рулем. Не надо курить за рулем или разговаривать по телефону. Если ведете беседу с пассажиром, постарайтесь не задумываться над ответом. Размышления за рулем на сложную тему отвлекает ваше внимание от дороги.

И напоследок запомните раз и навсегда: водитель ГЛАВНЫЙ в машине, он как капитан корабля, который имеет право выкинуть пассажира за борт, если тот угрожает безопасности корабля. Главный в машине ВСЕГДА водитель, даже если хозяин машины едет рядом.

Будешь мне указывать, вообще пешком пойдёшь!

  • Если вам не нравится музыка, которую включил пассажир — выключите ее. Протестующие могут идти пешком
  • Если в машине громко разговаривают и вас это категорически не устраивает, заткните ненужные разговоры
  • Не стесняйтесь остановиться и высадить пассажира, который своим поведением угрожает безопасности вождения, или откажитесь ехать дальше, если высаживаемый пассажир является хозяином машины
  • В первую очередь вас должна волновать безопасность пассажиров, а потом уже груза. Не бойтесь поломать рассаду помидоров на заднем сиденье неосторожным рывком руля, если это поможет избежать аварии. Или сломать свадебный торт за тридцать килорублей в попытке отклонится от встречной машины

Возможно, советы из этой заметки некоторым покажутся смешными и глупыми. Но соблюдая эти нехитрые правила, я был в легкой аварии в 2015 году и не собираюсь в них участвовать в дальнейшем, потому что на моей машине следующая авария точно будет последней.

Также рекомендую прочитать про особенности аккуратного вождения.

Python модуль для создания древовидной структуры даных на лету

Хочу представить на суд общественности модуль, который позволяет создавать древовидные структуры на лету. Сначала пример, потом сам модуль. Вопросы по модулю смело задавайте в комментариях к посту.

Пример использования

# -*- coding: utf-8 -*-
import cPickle as pickle
from Dictionary import Dictionary
 
# Создаем пустой объект "animalsDict"
animalsDict = Dictionary()
 
# Добавляем ветку "cats" и ноду "wild" со значением "Tiger"
animalsDict.cats.wild = 'Tiger'
# К ветке "cats" добавляем ноду "home" со значение "House"
animalsDict.cats.home = 'House'
# Добавляем ветку "dogs" одной строкой с нодами "wild" и "home"
animalsDict.dogs = Dictionary(wild='wolf', home='House')
# Выводим данные с префиксом "animals"
print "before dump:"
animalsDict.printf('animals')
 
# Сохраняем объект "animalsDict" в строку
data = pickle.dumps(animalsDict)
# Восстанавливаем данные в объект "animalsRestored"
animalsRestored = pickle.loads(data)
 
# Выводим данные с префиксом "animals2"
print
print "after dump:"
animalsRestored.printf("animals2")
 
# Удаляем ветку cats
del animalsRestored.cats
 
# Повторно выводим данные
print
print "after remove:"
animalsRestored.printf("animals2")
 
# Создаем объект только для чтения
p = Dictionary(read_only=True, x=2, y=3.5, z=1.0)
 
# Выводим объект "p" с префиксом "point"
print
print "read only:"
p.printf("point")
 
# Если это раскомментировать, будет исключение типа KeyError
# del p.x

Вывод

before dump:
animals.cats.home = House
animals.cats.wild = Tiger
animals.dogs.home = House
animals.dogs.wild = wolf
 
after dump:
animals2.cats.home = House
animals2.cats.wild = Tiger
animals2.dogs.home = House
animals2.dogs.wild = wolf
 
after remove:
animals2.dogs.home = House
animals2.dogs.wild = wolf
 
read only:
point.x = 2
point.y = 3.5
point.z = 1.0

Модуль Dictionary.py

Исходники программы на Python

import cPickle as pickle
 
 
class Dictionary:
    def __init__(self, read_only=False, **params):
        self.__dict__['__children__'] = {}
        self.__dict__['__readonly__'] = read_only
        for key, value in params.iteritems():
            self.__dict__['__children__'][key] = value
 
 
    def clear(self):
        for key, value in self.__dict__['__children__'].iteritems():
            if isinstance(value, Dictionary):
                value.clear()
        self.__dict__['__children__'].clear()
 
 
    def printf(self, prefix=None):
        for key in sorted(self.__dict__['__children__'].iterkeys()):
            value = self.__dict__['__children__'][key]
            if value is None:
                continue
            if isinstance(value, Dictionary):
                if prefix:
                    value.printf('%s.%s' % (prefix, key))
                else:
                    value.printf('%s' % key)
            else:
                if prefix:
                    print '%s.%s = %s' % (prefix, key, str(value))
                else:
                    print '%s = %s' % (key, str(value))
 
 
    def __getattr__(self, name):
        try:
            return self.__dict__['__children__'][name]
        except KeyError:
            if not self.__dict__['__readonly__']:
                value = self.__dict__['__children__'][name] = Dictionary()
                return value
            raise
 
 
    def __delattr__(self, name):
        if self.__dict__['__readonly__']:
            raise KeyError, "Read only structure."
        del self.__dict__['__children__'][name]
 
 
    def __setattr__(self, name, value):
        children = self.__dict__['__children__']
        old_value = children.get(name)
 
        if name not in children:
            if self.__dict__['__readonly__']:
                raise KeyError, "Read only structure."
        elif isinstance(old_value, Dictionary):
            if old_value:
                raise AttributeError, "Attribute %s has children: %s" % (repr(name), old_value)
 
        children[name] = value
 
 
    def __getitem__(self, name):
        return self.__getattr__(name)
 
 
    def __setitem__(self, name, value):
        self.__setattr__(name, value)
 
 
    def __delitem__(self, name):
        self.__delattr__(name)
 
 
    def __eq__(self, value):
        if isinstance(value, Dictionary):
            return repr(self) == repr(value)
        if isinstance(value, dict):
            return self.__dict__['__children__'] == value
        return value is None
 
 
    def __ne__(self, value):
        return not self.__eq__(value)
 
 
    def __nonzero__(self):
        return bool(self.__dict__['__children__'])
 
 
    def __str__(self):
        return str(repr(self))
 
 
    def __repr__(self):
        params = [('read_only=%s' % self.__dict__['__readonly__'])]
        for key in sorted(self.__dict__['__children__'].iterkeys()):
            value = self.__dict__['__children__'][key]
            params.append('%s=%s' % (key, repr(value)))
        return 'Dictionary(%s)' % ', '.join(params)
 
 
    def __len__(self):
        return len(self.__dict__['__children__'])
 
 
    def iterkeys(self):
        return self.__dict__['__children__'].iterkeys()
 
 
    def itervalues(self):
        return self.__dict__['__children__'].itervalues()
 
 
    def iteritems(self):
        return self.__dict__['__children__'].iteritems()
 
 
    def __iter__(self):
        return self.__dict__['__children__'].__iter__()
 
 
    def __setstate__(self, state):
        for key, name, value in state:
            if key == 'param':
                self.__dict__[name] = value
            elif key == 'value':
                self.__dict__['__children__'][name] = pickle.loads(value)
 
 
    def __getstate__(self):
        result = []
        result.append(('param', '__readonly__', self.__dict__['__readonly__']))
 
        for name, value in self.__dict__['__children__'].iteritems():
            result.append(('value', name, pickle.dumps(value)))
        return tuple(result)
 
 
    def __getinitargs__(self):
        return ()
 
 
    @staticmethod
    def parse(kwargs):
        kwargs = dict(kwargs)
        params = {}
 
        while kwargs:
            key, value = kwargs.popitem()
            uri = key.split(".")
            params_ptr = params
 
            if len(uri) == 1:
                params[key] = value
                continue
 
            for i in xrange(len(uri)):
                k = uri[i]
                if i == len(uri) - 1:
                    params_ptr[k] = value
                elif k not in params_ptr:
                    params_ptr[k] = {}
                params_ptr = params_ptr[k]
 
        def create(dictionary):
            result = {}
            for key, value in dictionary.iteritems():
                if isinstance(value, dict):
                    result[key] = create(value)
                else:
                    result[key] = value
            return Dictionary(read_only=True, **result)
 
        return create(params)

Блог Евгения Жирнова