2013-08-28 8 views
5

Mam duże pliki danych, które muszą być skopiowane z folderów źródłowych, aby budować foldery podczas naszej budowy Qmake/QtCreator. Ponieważ są one duże, chcę tylko, aby kopia była dostępna dla nowych/zmienionych plików. Naprawdę chciałbym uniknąć umieszczenia ich wszystkich w pliku projektu. Oto, co próbowałem:Jak zmusić QMake do kopiowania dużych plików danych tylko wtedy, gdy są one aktualizowane

Ta próba kopiowania plików danych kończy się niepowodzeniem, ponieważ celem jest folder DemoData. Dlatego kopia nie zostanie wykonana, jeśli pliki w folderze zostaną dodane lub zmienione. Tylko jeśli folder nie istnieje.

DemoData.commands = $$COPY_CMD $${SRC_DATA_DIR}DemoData $${BLD_DATA_DIR}DemoData 
DemoData.target += $${BLD_DATA_DIR}DemoData 
PRE_TARGETDEPS += $${BLD_DATA_DIR}DemoData 
QMAKE_EXTRA_TARGETS += DemoData 

To podejście kończy się niepowodzeniem, ponieważ element DemoData.target nie powinien zawierać listy wielu elementów. QMake umieszcza listę w cudzysłowach w wygenerowanym pliku Makefile, dzięki czemu staje się jednym celem.

DemoData.commands = $$COPY_CMD $${SRC_DATA_DIR}DemoData $${BLD_DATA_DIR}DemoData 
DEMO_DATA_FILES = $$files($${SRC_DATA_DIR}DemoData/*) 
for(FILE, DEMO_DATA_FILES){ 
    DemoData.target += $${BLD_DATA_DIR}DemoData\\$$basename(FILE) 
    PRE_TARGETDEPS += $${BLD_DATA_DIR}DemoData\\$$basename(FILE) 
} 
QMAKE_EXTRA_TARGETS += DemoData 

Ta próba kończy się niepowodzeniem, ponieważ (AFAICT) QMake nie obsługuje nazw zmiennych zawartych w innych zmiennych. Wydaje się, że jest to więcej niż jeden poziom podstawienia. Plik Makefile jest generowany, ale wszystkie cele DemoDataX nie mają żadnych wierszy poleceń. Wszystkie próby wyświetlenia zawartości pola "poleceń" generują błędy składni.

DEMO_DATA_FILES = $$files($${SRC_DATA_DIR}DemoData/*) 
DEMO_DATA_NAME = DemoData 
for(FILE, DEMO_DATA_FILES){ 
    $${DEMO_DATA_NAME}.target = $${FILE} 
    $${DEMO_DATA_NAME}.commands = $$COPY_CMD $${FILE} $${BLD_DATA_DIR}DemoData 
    PRE_TARGETDEPS += $${FILE} 
    QMAKE_EXTRA_TARGETS += $${DEMO_DATA_NAME} 
    DEMO_DATA_NAME = $${DEMO_DATA_NAME}X 
} 

To podejście działa, ale z dwoma niedociągnięciami. Mniejsza jest to, że należy wykonać oddzielny krok "make install". Najważniejsze jest to, że pliki są zawsze kopiowane bezwarunkowo. Ponieważ nasze pliki danych są duże, jest to niedopuszczalne czas.

DemoData.path = $${BLD_DATA_DIR}DemoData 
DemoData.files = $${SRC_DATA_DIR}DemoData/* 
INSTALLS += DemoData 

Czy istnieje sposób, aby to zrobić, czy pozostawiłem jakiś zewnętrzny skrypt lub ręcznie wygenerowany/utrzymany plik Makefile?

Odpowiedz

4

Użyj funkcji QMAKE_EXTRA_COMPILES.

# list your files in this variable. 
# Masks are available with $$files functions but 
# if your set of files changes (files added or removed) 
# your have to re-run qmake after that explicitly, not just make 
MYFILES = $$files($${PWD}/files/*.*) 

copy_files.name = copy large files 
copy_files.input = MYFILES 
# change datafiles to a directory you want to put the files to 
copy_files.output = $${OUT_PWD}/datafiles/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT} 
copy_files.commands = ${COPY_FILE} ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} 
copy_files.CONFIG += no_link target_predeps 

QMAKE_EXTRA_COMPILERS += copy_files 

Dodaj swoje duże pliki do zmiennej MYFILES. Dla każdego pliku reguła zostanie wygenerowana w pliku Makefile, który kopiuje plik do określonego katalogu (pliki danych w przykładzie). Oryginalny plik zostanie wymieniony jako zależność w regule (jest to domyślne zachowanie qmake), więc kopiowanie nastąpi tylko wtedy, gdy oryginalny plik jest aktualniejszy od istniejącej kopii. Wygenerowane reguły są wymienione jako zależności w regule pliku docelowego (copy_files.CONFIG + = target_predeps), więc kopiowanie nastąpi automatycznie przy każdej kompilacji.

Jedyne zastrzeżenie: jeśli twój zbiór plików jest dynamiczny (pliki są dodawane lub usuwane) możesz używać masek jak w moim przykładzie, ale musisz zachować ostrożność, aby wykonać qmake po zmianie zestawu. Pamiętaj, że Qt Creator tworzy projekty, uruchamiając make, a nie qmake. Najprostszym sposobem zapewnienia uruchomienia qmake jest modyfikacja pliku .pro.

Dla tych, którzy potrafią czytać rosyjski jest więcej informacji o QMAKE_EXTRA_COMPILERS here

+0

Wygląda na dobrą opcję. Nie będzie miał okazji spróbować tego przez jakiś czas. –

2

Czy potrzebujesz skryptu do pracy na różnych platformach? Osobiście nie użyłbym polecenia kopiowania, ale robocopy w Windows i rsync na Mac/Linux.

win32: $${DEMO_DATA_NAME}.commands = robocopy $${SRC_DIR} $${DST_DIR} $${FILE} /MIR /XO 
!win32: $${DEMO_DATA_NAME}.commands = rsync -aru $${FILE} $${BLD_DATA_DIR} 

Nie jestem pewien, co chcesz skopiować tutaj, ale masz pomysł, możesz dostosować pliki i/lub katalogi.

Parametry robocopii są opisane here.

  • /MIR Lustra drzewie katalogów
  • /XO Wyklucza starsze pliki.

Parametry Rsync są opisane here.

  • -a Archiwum
  • -r Recursive
  • -u Aktualizacja tylko gdy źródłem jest nowszy

Na marginesie, jeśli nie chcesz, aby uruchomić to polecenie make install, można ustawić ten dodatkowy cel jako zależność od projektu, który potrzebuje tych plików: theProjectNeedingThoseFiles.depends += DemoData.

+0

Należy zmienić 'robocopy' polecenie do' -robocopy' (dodać odrobinę z przodu), które w zasadzie mówi „Ignoruj ​​błędy tego polecenia "(nadal będzie wyświetlany komunikat o błędzie" ignorowany ", ale kontynuuj). Problem polega na tym, że Robocopy zwraca kod wyjścia '1', jeśli to się udało - ale' make' interpretuje to jako błąd i zatrzymuje wykonywanie pliku Makefile ... Zajęło mi to godziny, aby to zrozumieć ... Alternatywnie użyj 'robocopy [...] || rem', który spróbuje Robocopy i jeśli zwróci kod wyjścia 1 (który będzie), 'rem' (nic nie rób) będzie uruchamiany później - make będzie zakładać, że wszystko było w porządku. – mozzbozz

+0

Oczywiście oba rozwiązania są dalekie od ideału, ponieważ pierwszy z nich zanieczyści wyjście przez "ignorowany błąd [...]" - wiadomości, a drugi całkowicie zignoruje każdy błąd. Sugestie mile widziane;) – mozzbozz

Powiązane problemy